I would like to convert xml file format to another format; using XSL version 1.0 or 2.0.
Input XML file:
<ROOT_XML>
<Struct id="_6" name="Result" context="_1" members="_9 _10 _11 _13 _14 "/>
<FundamentalType id="_7" name="int" size="32" align="32"/>
<FundamentalType id="_8" name="float" size="32" align="32"/>
<Field id="_9" name="angle" type="_8" offset="0" context="_6"/>
<Field id="_10" name="row" type="_7" offset="32" context="_6"/>
<Field id="_11" name="cloth" type="_18" offset="96" context="_6"/>
<Destructor id="_13" name="EmptyClass" artificial="1" throw="" context="_6">
</Destructor>
<Constructor id="_14" name="Result" context="_6">
<Argument type="_20" location="f0:2" file="f0" line="2"/>
</Constructor>
<Constructor id="_15" name="Result" context="_6"/>
<FundamentalType id="_17" name="unsigned int" size="32" align="32"/>
<ArrayType id="_18" min="0" max="29u" type="_21" size="240" align="8"/>
<ReferenceType id="_19" type="_6" size="32" align="32"/>
<ReferenceType id="_20" type="_6c" size="32" align="32"/>
<FundamentalType id="_21" name="char" size="8" align="8"/>
</ROOT_XML>
Output XML file:
<Struct Result>
<Fields>
<Field name="angle" type="float" size="32"/>
<Field name="row" type="int" size="32"/>
<Field name="cloth" type="char" size="240"/>
</Fields>
</Struct>
The is an example on how to parse the 'members' attribute list
http://www.w3.org/1999/XSL/Transform" version = "1.0">
<xsl:template match="/ROOT_XML/Struct">
<Struct><xsl:value-of select="name"/>
<xsl:choose>
<xsl:when test="boolean(./@members)">
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="./@members"/>
<xsl:with-param name="delimiter" select="' '"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</Struct>
</xsl:template>
<!--############################################################-->
<!--## Template to tokenize strings ##-->
<!--############################################################-->
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<member>
<!-- get everything in front of the first delimiter -->
<xsl:value-of select="substring-before($list,$delimiter)"/>
</member>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<member>
<xsl:value-of select="$list"/>
</member>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This code is a starting point to extract the relevant id's from the 'members' attribute of the 'Struct' node, and later be used to emit only the 'Field' nodes.
In addition, the output XML file might contains more than one 'Struct' node, For Instance:
<Struct Result>
<Fields>
<Field name="angle" type="float" size="32"/>
<Field name="row" type="int" size="32"/>
<Field name="cloth" type="char" size="240"/>
</Fields>
</Struct>
<Struct Answer>
<Fields>
<Field name="direction" type="float" size="32"/>
<Field name="col" type="int" size="32"/>
<Field name="paper" type="char" size="232"/>
</Fields>
</Struct>
Thanks for the reply. still, I would like to emphasize the logic on how to get the xml output.
The xslt processor needs to parse the 'members' attribute of the Struct node. The 'members' attribute is a list of Field's ids.
In the above example:
Only "members=_9 _10 _11" are Field nodes! and therefore they should be output as done by Michael previously. The rest of the items in the list are omitted (i.e. members="_13 _14")
The combined code: (I need assistance to continue...) http://www.w3.org/1999/XSL/Transform" version = "1.0">
<Struct><xsl:value-of select="name"/>
<xsl:choose>
<xsl:when test="boolean(./@members)">
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="./@members"/>
<xsl:with-param name="delimiter" select="' '"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</Struct>
</xsl:template>
<!--############################################################-->
<!--## Template to tokenize strings ##-->
<!--############################################################-->
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<member>
<!-- get everything in front of the first delimiter -->
<xsl:value-of select="substring-before($list,$delimiter)"/>
<!-- TODO: select holds the member's id...
Q: how should we continue from here?? -->
</member>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<member>
<xsl:value-of select="$list"/>
<!-- TODO: select holds the member's id...
Q: how should we continue from here?? -->
</member>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Field[key('f-type', @type)]">
<xsl:variable name="f-type" select="key('f-type', @type)" />
<Field name="{@name}" type="{$f-type/@name}" size="{$f-type/@size}"/>
</xsl:template>
<xsl:template match="Field[key('a-type', @type)]">
<xsl:variable name="a-type" select="key('a-type', @type)" />
<xsl:variable name="f-type" select="key('f-type', $a-type/@type)" />
<Field name="{@name}" type="{$f-type/@name}" size="{$a-type/@size}"/>
</xsl:template>
<Struct Result>
is bad XML, by the way. It's possible to create this through XSLT, but not with theoutput
set toXML
. – Jongware