user3419276
user3419276

Reputation: 33

Sorting on one attribute removes another attribute from xml file

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) &lt; '100' 
                or 
                count(subfields/subfield/position/values) &lt; '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

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

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

Related Questions