0
votes

That's my very first question according to XSLT. I would like to transform a XML structure by using XSLT.

The relevant part of my XML source:

<field tag="ElementName">
  <subfield code="S">p</subfield>
  <subfield code="a">Content 1 for S=P</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">p</subfield>
  <subfield code="a">Content 2 for S=P</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">p</subfield>
  <subfield code="a">Content 3 for S=P</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">g</subfield>
  <subfield code="a">Content 1 for S=G</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">g</subfield>
  <subfield code="a">Content 2 for S=G</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">s</subfield>
  <subfield code="a">Content 1 for S=S</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">s</subfield>
  <subfield code="a">Content 2 for S=S</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">s</subfield>
  <subfield code="a">Content 3 for S=S</subfield>
</field>
<field tag="ElementName">
  <subfield code="S">s</subfield>
  <subfield code="a">Content 4 for S=S</subfield>
</field>

Next what I would like the XML to look like after transformation:

<field tag="ElementName_P">
  <subfield code="a">Content 1 for S=P</subfield>
  <subfield code="a">Content 2 for S=P</subfield>
  <subfield code="a">Content 3 for S=P</subfield>
</field>
<field tag="ElementName_G">
  <subfield code="a">Content 1 for S=G</subfield>
  <subfield code="a">Content 2 for S=G</subfield>
</field>
<field tag="ElementName_S">
  <subfield code="a">Content 1 for S=S</subfield>
  <subfield code="a">Content 2 for S=S</subfield>
  <subfield code="a">Content 3 for S=S</subfield>
  <subfield code="a">Content 4 for S=S</subfield>
</field>

I know how to get the attribute values and the field values using xsl:variable and xsl:value-of. What I would like to know is how to group the contents from the subfields with code="a". Have been trying for hours. Are there any possibilities using XPath?

Thx for support!

1
This is a grouping question. Do a search - it's one of the most frequently asked questions here. Note that answers are different for XSLT 1.0 or 2.0.michael.hor257k

1 Answers

0
votes

As example how this can be done in XSLT 1.0:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" encoding="utf-8" method="xml" 
            omit-xml-declaration="yes" />
<xsl:strip-space elements="*"/>
  <xsl:key name="sCode" match="subfield[@code='S']" use="." />
  <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
  <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

  <xsl:template match="field">
    <xsl:for-each select="subfield[generate-id() =
                          generate-id(key('sCode', .)[1])]">
      <xsl:variable name="elements" select="key('sCode', .)" />
      <field>
        <xsl:attribute name="tag" select="concat('ElementName_', 
                                  translate($elements, $smallcase, $uppercase))"/>
        <xsl:apply-templates select="//subfield[(./text() =  $elements)]"
                             mode="sorted"/>  
      </field>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="subfield" mode="sorted">
     <xsl:copy>
        <xsl:attribute name="code" select="."/>
        <xsl:value-of select="./following-sibling::subfield[@code='a']"/>
     </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

when applied to your input XML has the ouput

<field tag="ElementName_P">
  <subfield code="p">Content 1 for S=P</subfield>
  <subfield code="p">Content 2 for S=P</subfield>
  <subfield code="p">Content 3 for S=P</subfield>
</field>
<field tag="ElementName_G">
  <subfield code="g">Content 1 for S=G</subfield>
  <subfield code="g">Content 2 for S=G</subfield>
</field>
<field tag="ElementName_S">
  <subfield code="s">Content 1 for S=S</subfield>
  <subfield code="s">Content 2 for S=S</subfield>
  <subfield code="s">Content 3 for S=S</subfield>
  <subfield code="s">Content 4 for S=S</subfield>
</field>

In case you're using XSLT 2.0 it wouldn't be necessary to translate the code value for the ElementName tag in the output but you could just use the function uppercase().

As references for XSLT grouping you can have a look at e.g. http://www.jenitennison.com/xslt/grouping/muenchian.xml and http://www.dpawson.co.uk/xsl/sect2/N4486.html