ome
ome

Reputation: 11

convert xml (Freeplane app) to json

I try to convert some xml files (from Freeplane app) to json with xsl syntax ; the result to reach looks like that:

[
    {"title": "Animalia", "children": [
        {"title": "Chordate", "children": [
            {"title": "Mammal", "children": [
                {"title": "Primate", "children": [
                    {"title": "Primate"},
                    {"title": "Carnivora"}
                ]},
                {"title": "Carnivora", "children": [
                    {"title": "Felidae"}
                ]}
            ]}
        ]},
        {"title": "Arthropoda", "children": [
            {"title": "Insect", "children": [
                {"title": "Diptera"}
            ]}
        ]}
    ]}
]

Here is my xsl file :

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no"/>
  <xsl:param name="indent-increment" select="'    '" />

  <xsl:template match="map">
    <!-- Ignores root 'node' -->
    <xsl:apply-templates select="node/node"/>
  </xsl:template>

  <xsl:template match="node">
    <xsl:param name="indent" select="'&#x0A;'"/>
    <xsl:variable name="indent0" select="$indent" />
    <xsl:variable name="indent1" select="concat($indent, $indent-increment)" />

    <xsl:if test="position() &gt; 1">, </xsl:if>

    <xsl:text>[</xsl:text>

    <xsl:value-of select="$indent1"/>
    <xsl:text>{"title": "</xsl:text>
    <!-- Need to replace " with \" in @TEXT strings -->
    <xsl:value-of disable-output-escaping='yes' select="@TEXT"/>
    <xsl:text>"</xsl:text>

    <!-- Recursion 
    <xsl:if test="@LINK">
      <xsl:text>,</xsl:text>
      <xsl:value-of select="$indent1"/>
      <xsl:text>url: "</xsl:text>
      <xsl:value-of disable-output-escaping='yes' select="@LINK"/>
      <xsl:text>"</xsl:text>
    </xsl:if>
    -->


    <xsl:if test="node">
      <xsl:text>,</xsl:text>
      <xsl:value-of select="$indent1"/>
      <xsl:text>"children": </xsl:text>

      <!-- Recursion -->
      <xsl:apply-templates select="node">
        <xsl:with-param name="indent" select="$indent1"/>
      </xsl:apply-templates>

      <xsl:text>}</xsl:text>
    </xsl:if>

      <xsl:if test="not(node)">
          <xsl:text>}</xsl:text>      
    </xsl:if>


    <xsl:value-of select="$indent"/>
    <xsl:text>]</xsl:text>

  </xsl:template>
</xsl:stylesheet>

I've tried a lot of combinations in xsl file but I didn't succeed in putting the right syntax to have a clean json at the end. And my json file gives me this (wrong) output :

[
    {"title": "Animalia",
    "children": [
        {"title": "Chordate",
        "children": [
            {"title": "Mammal",
            "children": [
                {"title": "Primate",
                "children": [
                    {"title": "Carnivora",
                    "children": [
                        {"title": "Felidae"}
                    ]}
                ]}
            ]}
        ]}
    ], [
        {"title": "Arthropoda",
        "children": [
            {"title": "Insect",
            "children": [
                {"title": "Diptera"}
            ]}
        ]}
    ]}
]

I know my xsl file is wrong but at this point, I can't find the right solution, so if someone have any idea to how make a well made xsl file to convert into the json I want, I would be very pleased... Thanks

Here is the xml file generated by the Freemind app.:

<map version="1.0.1">
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
<node CREATED="1484301934011" ID="ID_389012734" MODIFIED="1484301940301" TEXT="test">
<node CREATED="1484301961212" MODIFIED="1484301961212" POSITION="right" TEXT="Animalia">
<node CREATED="1484301961212" MODIFIED="1484301961212" TEXT="Chordate">
<node CREATED="1484301961213" MODIFIED="1484301961213" TEXT="Mammal">
<node CREATED="1484301961214" MODIFIED="1484301961214" TEXT="Primate">
<node CREATED="1484301961214" MODIFIED="1484301961214" TEXT="Carnivora">
<node CREATED="1484301961215" MODIFIED="1484301961215" TEXT="Felidae"/>
</node>
</node>
</node>
</node>
<node CREATED="1484301961216" MODIFIED="1484301961216" TEXT="Arthropoda">
<node CREATED="1484301961216" MODIFIED="1484301961216" TEXT="Insect">
<node CREATED="1484301961217" MODIFIED="1484301961217" TEXT="Diptera"/>
</node>
</node>
</node>
</node>
</map>

Upvotes: 0

Views: 305

Answers (1)

Sprotty
Sprotty

Reputation: 5983

Have a look at xsltjson, it probably does exactly what you want as is, but if not you may be able to tweak it to get the output your after

UPDATE :

Given your XML, you are transforming the data and converting it to json. I suggest you treat these to operations separately, convert the XML to a format that suites then convert it to json. I would recommend using an existing library to do the XML to JSON conversion as its fiddly and a home made solution is likely to be buggy.

I suggest you transform your XML to something like

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Liquid Studio 2017 - Developer Bundle Edition (Trial) 15.0.0.7084 (https://www.liquid-technologies.com) -->
<children>
    <title>test</title>
    <children xmlns:json="http://json.org/" json:force-array="true">
        <title>Animalia</title>
        <children json:force-array="true">
            <title>Chordate</title>
            <children json:force-array="true">
                <title>Mammal</title>
                <children json:force-array="true">
                    <title>Primate</title>
                    <children json:force-array="true">
                        <title>Carnivora</title>
                        <children json:force-array="true">
                            <title>Felidae</title>
                        </children>
                    </children>
                </children>
            </children>
        </children>
        <children json:force-array="true">
            <title>Arthropoda</title>
            <children json:force-array="true">
                <title>Insect</title>
                <children json:force-array="true">
                    <title>Diptera</title>
                </children>
            </children>
        </children>
    </children>
</children>

then use xsltjson to transform it to json

{
    "": {
        "children": {
            "title": "test",
            "children": [
                {
                    "title": "Animalia",
                    "children": [
                        {
                            "title": "Chordate",
                            "children": [
                                {
                                    "title": "Mammal",
                                    "children": [
                                        {
                                            "title": "Primate",
                                            "children": [
                                                {
                                                    "title": "Carnivora",
                                                    "children": [
                                                        {
                                                            "title": "Felidae"
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "title": "Arthropoda",
                            "children": [
                                {
                                    "title": "Insect",
                                    "children": [
                                        {
                                            "title": "Diptera"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
}

Something like this should do it

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:json="http://json.org/"
                 exclude-result-prefixes="xs xsl json">
    <xsl:include href="xml-to-json.xsl"></xsl:include>

    <xsl:template match="/">
        <xsl:variable name="myXml">
            <children>
                <xsl:apply-templates select="map/*"></xsl:apply-templates>
            </children>
        </xsl:variable>
        <xsl:value-of select="json:generate($myXml)"/>

    </xsl:template>

    <xsl:template match="node">
        <title>
            <xsl:value-of select="@TEXT"></xsl:value-of> 
        </title>
        <xsl:for-each select="node">
            <children json:force-array="true" xmlns:json="http://json.org/">
                <xsl:apply-templates select="."></xsl:apply-templates>
            </children>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions