Jim C Jim C - 4 months ago 11
Java Question

how transform from xml based on attributes to json and ignore the attributes from especific elements by using XSLT/XSL

I believe my question provides a good idea what I am trying to do. BTW, find below the incoming xml and desired json output.

I found an excellent answer here Problems converting XML to JSON using XSLT about how to move from xml to json but my xml is a bit different. Kindly, note below that the values are part of the attributes. Additionally, I want to ignore the attributes from c:item. In other words, cod and package must be ignored. I know how to transform such xml based on attributes to another xml based on element values and then transform this new xml in json format but it seems to me a bit strange the first step (from xml to another xml) since I want the json only. I know from xml to xml thanks to the excellent answer just provided here while transforming attributes to element with XSLT how ignore only the attributes in parent element

incoming xml

<c:product xmlns:c="myapp">
<c:item cod="789">
<c:aa name="024" value="123"/>
<c:bbb name="0105" value="123456"/>
<c:bbb name="0122" value="T"/>
<c:aa name="071" value="00000001"/>
</c:item>
<c:item package="123" cod="11111">
<c:aa name="002" value="753"/>
<c:aa name="003" value="456"/>
<c:bbb name="0146" value="147852"/>
</c:item>
</c:product>


output xml just to exemplify the extra step I have to do with my current knolege, i.e, if I am obligated to do the extra step from xml to xml just to take out the attributes from c:item and formating the values as element instead of attributes before going from xml to json

<product>
<item>
<aa>
<name>024</name>
<value>123</value>
</aa>
<bbb>
<name>0105</name>
<value>123456</value>
</bbb>
<bbb>
<name>0122</name>
<value>T</value>
</bbb>
<aa>
<name>071</name>
<value>00000001</value>
</aa>
</item>
<item>
<aa>
<name>002</name>
<value>753</value>
</aa>
<aa>
<name>003</name>
<value>456</value>
</aa>
<bbb>
<name>0146</name>
<value>147852</value>
</bbb>
</item>
</product>


the current xls used for transform from xml to xml

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:c="myapp"
exclude-result-prefixes="c">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>

<xsl:template match="c:item">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>

<xsl:template match="@*">
<xsl:element name="{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>

</xsl:stylesheet>


outcome and desired json (well just imagine the last xml transformed in a json file)

{
{
"aa" : {"024":"123"}
"bbb" : {"0105","123456"}
"bbb" : {"0122","T"}
"aa" : {"071","00000001"}
}
{
{
...
}
}


**** Edited July 31th

output based on Michael Kay answer:

"aa" : {"024":"123"}"bbb" : {"0105":"123456"}"bbb" : {"0122":"T"}"aa" : {"071":"00000001"}"aa" : {"002":"753"}"aa" : {"003":"456"}"bbb" : {"0146":"147852"}


XLS used based on Michael Kay answer and generating above outcome

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:c="myapp" exclude-result-prefixes="c">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="c:item/*">
<xsl:text>"</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>" : {"</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>":"</xsl:text>
<xsl:value-of select="@value"/>
<xsl:text>"}</xsl:text>
</xsl:template>
</xsl:stylesheet>

Answer

The XSLT you have shown is on the right path, but you are missing a few things

  1. No template handling the c:item itself to wrap the child nodes in { }
  2. No output of commas and line-breaks to separate objects
  3. No handling of the root element c:product to create a child array (so you have valid JSON)

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0" 
                xmlns:c="myapp" exclude-result-prefixes="c">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*[c:item]">
    <xsl:text>[&#10;</xsl:text>
    <xsl:apply-templates select="c:item"/>
    <xsl:text>]&#10;</xsl:text>
</xsl:template>

<xsl:template match="c:item">
    <xsl:text>  {&#10;</xsl:text>
        <xsl:apply-templates />
    <xsl:text>  }</xsl:text>
    <xsl:if test="following-sibling::c:item">
        <xsl:text>,</xsl:text>
    </xsl:if>
    <xsl:text>&#10;</xsl:text>
</xsl:template>

<xsl:template match="c:item/*">
        <xsl:text>    "</xsl:text>
        <xsl:value-of select="local-name()" />
        <xsl:text>" : {"</xsl:text>
        <xsl:value-of select="@name" />
        <xsl:text>":"</xsl:text><xsl:value-of select="@value" />
        <xsl:text>"}</xsl:text>
        <xsl:if test="following-sibling::*">
            <xsl:text>,</xsl:text>
        </xsl:if>
        <xsl:text>&#10;</xsl:text>
</xsl:template>
</xsl:stylesheet>

When you apply this XSLT to the following XML

<c:product xmlns:c="myapp">
       <c:item cod="789">
              <c:aa name="024" value="123"/>
              <c:bbb name="0105" value="123456"/>
              <c:bbb name="0122" value="T"/>
              <c:aa name="071" value="00000001"/>
       </c:item>
       <c:item package="123" cod="11111">
              <c:aa name="002" value="753"/>
              <c:aa name="003" value="456"/>
              <c:bbb name="0146" value="147852"/>
       </c:item>
</c:product>

The following is output

[
  {
    "aa" : {"024":"123"},
    "bbb" : {"0105":"123456"},
    "bbb" : {"0122":"T"},
    "aa" : {"071":"00000001"}
  },
  {
    "aa" : {"002":"753"},
    "aa" : {"003":"456"},
    "bbb" : {"0146":"147852"}
  }
]

This doesn't actually match the desired output in your question, but the output you are shown isn't actually valid JSON.

See this answer in action at http://xsltransform.net/ejivdGD

Comments