2

I'm practicing some XSL and using this XML document as a simple example:

<?xml version="1.1" encoding="UTF-8"?>

<zoo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="zoo.xsd" >
    <animals>
        <animal type="lion">
            <name>Zeus</name>
            <gender>M</gender>
            <eats>antelope</eats>
            <eats>monkey</eats>
        </animal>
        <animal type="monkey">
            <name>Fredo</name>
            <gender>M</gender>
            <eats>banana</eats>
            <iseatenby>lion</iseatenby>
        </animal>
        <animal type="lion">
            <name>Here</name>
            <gender>F</gender>
            <eats>antelope</eats>
            <eats>monkey</eats>
        </animal>
        <animal type="antelope">
            <name>Annie</name>
            <gender>F</gender>
            <eats>grass</eats>
            <iseatenby>lion</iseatenby>
        </animal>
        <animal type="elephant">
            <name>Moses</name>
            <gender>M</gender>
            <eats>leaves</eats>
        </animal>
    </animals>
</zoo>

I've been able to get some basic info via my XSL doc, but I'm stuck on one thing right now: how can I get all of the results if there are more than one? For example, in my document, some animals have multiple "eats" elements. I want to display them in a comma-separated string; eventually I want to transform each animal's elements into attributes and just have a single attribute for each. (Using my previous example, the new animal element lion's "eats" attribute would look like this: eats="antelope, monkey" )

Could someone please explain how I would do something like this with XSL?? Any help is much appreciated. :)

ThinkingStiff
  • 64,767
  • 30
  • 146
  • 239
Chris V.
  • 1,123
  • 5
  • 22
  • 50

2 Answers2

2

not a perfect though :)

try it now hope it helps .. I am converting each element as attribute ..

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//animal">
    <xsl:copy>
      <!--copies all other elements as attributes-->
      <xsl:for-each select="*[name()!='eats']">
        <xsl:attribute name="{name()}">
          <xsl:apply-templates select = "text()"/>
        </xsl:attribute>
      </xsl:for-each> 

      <xsl:attribute name="eats">

        <!-- Go to <eats/> node -->
        <xsl:for-each select="eats">

          <!--insearts string ", " if it has preceding values already :) -->
          <xsl:if test="preceding-sibling::eats">
            <xsl:text>, </xsl:text>
          </xsl:if>

          <!--copies all the text :) -->
          <xsl:apply-templates select="text()"/>

        </xsl:for-each>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Rookie Programmer Aravind
  • 11,952
  • 23
  • 81
  • 114
  • W3 school's tester doesn't seem to like this answer either :( It just outputs a blank page. I'll try it elsewhere. – Chris V. Jan 30 '12 at 05:08
  • oh! actually I am missing `` statement, I think w3schools doesn't like it .. :| let me edit it and post .. – Rookie Programmer Aravind Jan 30 '12 at 05:10
  • I actually noticed that just a second ago, tried adding to no avail :( Could I test the code in an IDE like Eclipse or just Notepad++ or something? I haven't actually had any experience with testing my xsl outside of W3 school's online tester. – Chris V. Jan 30 '12 at 05:16
  • @ChrisV. bro you won't get any output there in w3schools :( it supports only html output.. :| – Rookie Programmer Aravind Jan 30 '12 at 05:17
  • Thanks Aravind, xsltcake was awesome - exactly what I was looking for! :) – Chris V. Jan 30 '12 at 06:03
  • 1
    @infantprogrammer'Aravind': You are welcome :). BTW, I wouldn't recommend xsltcake -- an online transformation executor cannot be reliable and available anytime. Also, they are using the XSLT processor of the user's browser, so often two different users using different browsers get different results from the same transformation. – Dimitre Novatchev Jan 30 '12 at 12:56
  • Dimitre - I put together XsltCake I can see you dislike it quite a bit; constantly discouraging it's use. On the grounds that it might not be online - that's the internet, one could say don't use Stackoverflow for help because it might be offline. But we don't, of course. It's intended usage was to help facilitate "playing" with XSLT - and provide somewhere to share XSLT suggestions with other developers. Would you be happier with the service if it used server side XSL transformations? – joshcomley Jan 31 '12 at 09:06
1

Use this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="zoo/animals">
    <xsl:copy>
      <xsl:apply-templates select="animal"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="animal">
    <xsl:copy>
      <xsl:attribute name="eats">
        <xsl:for-each select="eats">
          <xsl:value-of select="."/>

          <xsl:if test="position() != last()">
            <xsl:text>,</xsl:text>
          </xsl:if>
        </xsl:for-each>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Reference:

The position function returns a number equal to the context position from the expression evaluation context. The last function returns a number equal to the context size from the expression evaluation context.

xsl:if checks if the current node isn't last node in context. If so, outputs ,.

http://www.w3.org/TR/xpath/#function-last

Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • Could you explain the xsl:if? Is that simply saying if this is the same element then append it? Also could you refresh my memory as to waht position() and last() return? EDIT: I just tried out your answer on W3 school's XSLT Tryit Editor ( http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog ) and it doesn't seem to work :/ – Chris V. Jan 30 '12 at 05:01
  • @ChrisV., I've updated my answer. Maybe this tester supports only `XHTML` output, because I tested my code, it works perfectly. – Kirill Polishchuk Jan 30 '12 at 05:11
  • Great answer and explanation, Kirill. :) Thanks for that! – Chris V. Jan 30 '12 at 05:18