Reputation: 33
I want sort the xml data based on count attribute and select first 100 values.
I have written this xsl. But it is removing @code from indicator tag which is required for further processing.
<xsl:template match="node()|@*">
<xsl:if test="//field
[count(indicators/indicator/values) < '100'
or
count(subfields/subfield/position/values) < '100'
]">
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:sort select="@count"
data-type="number"
order="descending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:if>
</xsl:template>
Please help to find 100 highest values and @code attribute which is removed after sorting from indicator tag.
Upvotes: 1
Views: 114
Reputation: 22617
Do not modify the identity transform. It is better to leave that template intact and write others as you need them: One to match the position
element (to be able to sort its child elements):
<xsl:template match="position">
and another one that matches values
elements if their position exceeds 100:
<xsl:template match="position/values[position() gt 100]"/>
I assume that by "sorting XML data" you meant sorting the values
elements inside position
. Also, I think by "select first 100 values" you meant selecting the first 100 values
elements inside position
.
Stylesheet (XSLT 2.0)
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="position">
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:sort select="@count" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="indicator/values[position() gt 100]|position/values[position() gt 100]"/>
</xsl:transform>
The stylesheet assumes that there are values
elements other than the ones inside indicator
and position
. If this is not the case, the following template will do:
<xsl:template match="values[position() gt 100]"/>
XML Output
<?xml version="1.0" encoding="UTF-8"?>
<field count="3159" tag="461">
<indicators>
<indicator code="1">
<values count="3159" value=" "/>
</indicator>
<indicator code="2">
<values count="3159" value="1"/>
</indicator>
</indicators>
<subfields>
<subfield code="3" count="3497">
<position>
<values count="32" value="200000190420020805152452"/>
<values count="28" value="200000000220020805151840"/>
<values count="9" value="200000190720020805152453"/>
<values count="8" value="200000190520020805152453"/>
<values count="6" value="200000190820020805152454"/>
<values count="3" value="200000190920020805152454"/>
<values count="1" value="200000000120020805151840"/>
<values count="1" value="200000190620020805152453"/>
</position>
</subfield>
</subfields>
</field>
Note: A more reasonable input XML would of course contain more than 100 values
elements to test whether they are sent to output or not.
Upvotes: 2