3

I'm new with xsl . I am having below xml:

    <record>
<fruit>Apples</fruit>
<fruit>Oranges</fruit>
<fruit>Bananas</fruit>
<fruit>Plums</fruit>
<vegetable>Carrots</vegetable>
<vegetable>Peas</vegetable>
<candy>Snickers</candy>

I want to use key function and have an output file:

     <record> 1
--<fruit> 4
--<vegetable> 2
--<candy> 1

Any solutions?

1
  • Are those hyphens part of the expected output? Do you really want output with unclosed XML tags? Commented Jan 12, 2013 at 6:01

2 Answers 2

2

As easy as this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:key name="kElemByName" match="*" use="name()"/>

 <xsl:template match=
  "*[not(generate-id()=generate-id(key('kElemByName',name())[1]))]"/>

 <xsl:template match="*">
  <xsl:value-of select=
  "concat('&lt;',name(),'> ', count(key('kElemByName',name())),'&#xA;')"/>
  <xsl:apply-templates select="*"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<record>
    <fruit>Apples</fruit>
    <fruit>Oranges</fruit>
    <fruit>Bananas</fruit>
    <fruit>Plums</fruit>
    <vegetable>Carrots</vegetable>
    <vegetable>Peas</vegetable>
    <candy>Snickers</candy>
</record>

the wanted, correct result is produced:

<record> 1
<fruit> 4
<vegetable> 2
<candy> 1
Sign up to request clarification or add additional context in comments.

1 Comment

Can you show me the way have result:/n <record> 1 --<fruit> 4 --<veget> 2 --<candi> 1
1

To include the hyphens (I will use Dimitre's answer as a base, so please give him the credit he is due), you can do this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:key name="kElemByName" match="*" use="name()"/>

  <xsl:template match=
  "*[not(generate-id()=generate-id(key('kElemByName',name())[1]))]">
    <xsl:apply-templates select="*" />
  </xsl:template>

  <xsl:template match="*">

    <xsl:apply-templates select="ancestor::*" mode="hyphens" />

    <xsl:value-of select=
       "concat('&lt;',name(),'> ', count(key('kElemByName',name())),'&#xA;')"/>
    <xsl:apply-templates select="*"/>
  </xsl:template>

  <xsl:template match="*" mode="hyphens">
    <xsl:text>--</xsl:text>
  </xsl:template>
</xsl:stylesheet>

With the original input, this produces:

<record> 1
--<fruit> 4
--<vegetable> 2
--<candy> 1

With a more deeply nested input,

<record>
  <fruit>
    Apples
  </fruit>
  <fruit>
    <citrus>Grapefruits</citrus>
    <citrus>Oranges</citrus>
    <citrus>Lemons</citrus>
  </fruit>
  <fruit>Bananas</fruit>
  <fruit>
    <pitted>Plums</pitted>
    <pitted>Apricots</pitted>
    <pitted>Peaches</pitted>
  </fruit>
  <vegetable>Carrots</vegetable>
  <vegetable>Peas</vegetable>
  <candy>
    <chocolate>Snickers</chocolate>
    <chocolate>Milky Way</chocolate>
    <chocolate>Hersheys</chocolate>
  </candy>
  <candy>
    <hard>Lozenges</hard>
    <hard>Lollipops</hard>
  </candy>
</record>

You get:

<record> 1
--<fruit> 4
----<citrus> 3
----<pitted> 3
--<vegetable> 2
--<candy> 2
----<chocolate> 3
----<hard> 2

How's that?

2 Comments

+1 for the <xsl:apply-templates select="ancestor::*" mode="hyphens" /> - very elegant, and an idiom I will have to remember for future reference.
Thanks @IanRoberts! Here's another case where I used a similar technique: stackoverflow.com/a/14274683/1945651 In this post here, a <xsl:for-each select="ancestor::*"><xsl:text>--<xsl:text></xsl:for-each> could've been just as good, but the other thread actually makes use of the template in more than one place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.