Sort XML File using XSLT -
i sorting xml file using xslt , facing small problem here..
my xml file given below:
<?xml version="1.0" encoding="iso-8859-1"?> <bulkcmconfigdatafile xmlns="a.xsd" xmlns:xn="b.xsd" xmlns:subs="c.xsd" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="a.xsd a.xsd"> <fileheader fileformatversion="32.615 v5.0"/> <configdata dnprefix="" log="0" mediation="false"> <subs:sumsubscriberprofile id="378466"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>1</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> <subs:sumsubscriberprofile id="378460"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>2</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> </configdata> <filefooter datetime="2015-03-14t10:10:10"/> </bulkcmconfigdatafile>
and using following style sheet:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns="a.xsd" xmlns:xn="b.xsd" xmlns:subs="c.xsd"> <xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-1" /> <xsl:strip-space elements="*" /> <xsl:param name="outermatchelement" /> <xsl:param name="innermatchelement" /> <xsl:param name="sortby" /> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="*[name()=$outermatchelement]"> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:choose> <xsl:when test="count(*[name()=$innermatchelement]) = 0"> <xsl:apply-templates select="*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> </xsl:when> <xsl:when test="count(*[name()=$innermatchelement]) = 1"> <xsl:apply-templates select="*[name()=$innermatchelement]/*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="*[name()=$innermatchelement]"> <xsl:sort select="*[name()=$sortby]/@id" data-type="number" /> </xsl:apply-templates> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> </xsl:stylesheet>
where outermatchelement = bulkcmconfigdatafile, innermatchelement=configdata , sortby=subs:sumsubscriberprofile
i getting following result using stylesheet:
<?xml version="1.0" encoding="iso-8859-1"?><bulkcmconfigdatafile xmlns="a.xsd" xmlns:xn="b.xsd" xmlns:subs="c.xsd" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="configdata.xsd configdata.xsd"> <subs:sumsubscriberprofile id="378460"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>2</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> <subs:sumsubscriberprofile id="378466"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>1</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> </bulkcmconfigdatafile>
expected output following:
<?xml version="1.0" encoding="iso-8859-1"?> <bulkcmconfigdatafile xmlns="a.xsd" xmlns:xn="b.xsd" xmlns:subs="c.xsd" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="configdata.xsd configdata.xsd"> <fileheader fileformatversion="32.615 v5.0"/> <configdata dnprefix="" log="0" mediation="false"> <subs:sumsubscriberprofile id="378460"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>2</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> <subs:sumsubscriberprofile id="378466"> <subs:sumsubscriptionprofile id="1"> <subs:imsserviceprofile id="1" modifier="create"> <subs:attributes> <subs:chargingidx>1</subs:chargingidx> </subs:attributes> </subs:imsserviceprofile> </subs:sumsubscriptionprofile> </subs:sumsubscriberprofile> </configdata> <filefooter datetime="2015-03-14t10:10:10"/> </bulkcmconfigdatafile>
you notice difference file header , file footer tags missing in output getting, please guide me how resolve issue?i trying make sorting process generic xml files.
in given input sample have 1 element matching $innermatchelement
variable, second xsl:when
applies. however, in relevant block of code gets executed in case, selecting child elements of "innermatchelement" element, other children ignored.
try changing second xsl:when
instead.
<xsl:when test="count(*[name()=$innermatchelement]) = 1"> <xsl:apply-templates select="*[following-sibling::*[name()=$innermatchelement]]" /> <xsl:apply-templates select="*[name()=$innermatchelement]/*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> <xsl:apply-templates select="*[preceding-sibling::*[name()=$innermatchelement]]" /> </xsl:when>
so, select elements occur before "innermatchelement" elements, select inner match one, , select elements occur after it.
you may have add similar lines other 2 conditions.
note, if want "innermatchelement" tag too, can achieve creating new 1 xsl:element
<xsl:when test="count(*[name()=$innermatchelement]) = 1"> <xsl:apply-templates select="*[following-sibling::*[name()=$innermatchelement]]" /> <xsl:element name="{$innermatchelement}"> <xsl:apply-templates select="*[name()=$innermatchelement]/@*" /> <xsl:apply-templates select="*[name()=$innermatchelement]/*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> </xsl:element> <xsl:apply-templates select="*[preceding-sibling::*[name()=$innermatchelement]]" /> </xsl:when>
alternatively, make better use of template matching. try xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns="a.xsd" xmlns:xn="b.xsd" xmlns:subs="c.xsd"> <xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-1" /> <xsl:strip-space elements="*" /> <xsl:param name="outermatchelement" select="'bulkcmconfigdatafile'" /> <xsl:param name="innermatchelement" select="'configdata'" /> <xsl:param name="sortby" select="'subs:sumsubscriberprofile'" /> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="*[name()=$outermatchelement]"> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:choose> <xsl:when test="count(*[name()=$innermatchelement]) = 0"> <xsl:apply-templates select="*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> </xsl:when> <xsl:when test="count(*[name()=$innermatchelement]) = 1"> <xsl:apply-templates select="*[name()=$innermatchelement]" mode="single" /> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="*[name()=$innermatchelement]"> <xsl:sort select="*[name()=$sortby]/@id" data-type="number" /> </xsl:apply-templates> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> <xsl:template match="*[name()=$innermatchelement]" mode="single"> <xsl:apply-templates select="preceding-sibling::*" /> <xsl:copy> <xsl:apply-templates select="@*" /> <xsl:apply-templates select="*[name()=$sortby]"> <xsl:sort select="@id" data-type="number" /> </xsl:apply-templates> </xsl:copy> <xsl:apply-templates select="following-sibling::*" /> </xsl:template> </xsl:stylesheet>
as aside, error in xslt 1.0 have variable in template match (see http://www.w3.org/tr/xslt#section-defining-template-rules), should fail
<xsl:template match="*[name()=$outermatchelement]">
however, xslt 1.0 allow it, possibly in case. if switch processor gets error, solution this...
<xsl:template match="*"> <xsl:choose> <xsl:when test="name()=$outermatchelement"> <!-- existing code --> </xsl:when> <xsl:otherwise> <!-- identity template --> </xsl:otherwise> </xsl:choose> </xsl:template>
Comments
Post a Comment