xsl-list
[Top] [All Lists]

Re: [xsl] Generate separate elements, not just attribute values

2017-03-23 15:01:41
On 23.03.2017 19:23, Charles O'Connor coconnor(_at_)ariessys(_dot_)com wrote:
Hi all,

Extreme novice here, so I appreciate your help.

Using XSLT 2.0 (explained later) and Saxon9 HE.

I have JATS 1.1 (archiving) input:

. . .

<contrib-group>
        <contrib contrib-type="author">
                <name>
                        <surname>Franzke</surname>
                        <given-names>Christian L. E.</given-names>
                </name>
        </contrib>
        <aff id="aff2">Meteorological Institute and Center for Earth System Research and Sustainability 
(CEN), <institution>University of Hamburg</institution>, <country>Germany</country></aff>
        <aff id="aff3">Department of Cheddar, <institution>University of Curds and 
Whey</institution>, <country>Land of Cheese</country></aff>
</contrib-group>

. . .

To make it easier for our engineers to recognize relationships between <contrib>s and 
<aff>s in cases where they are related through nesting in a <contrib-group>, not 
<xref>s, I wrote a small .xsl:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns:xs="http://www.w3.org/2001/XMLSchema"; exclude-result-prefixes="xs" 
version="2.0">
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//contrib[not(xref/@ref-type='aff')]">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
            <xsl:element name="xref">
                <xsl:attribute name="ref-type">aff</xsl:attribute>
                <xsl:attribute name="rid">
                    <xsl:value-of select="parent::contrib-group/aff/@id"/>
                </xsl:attribute>
            </xsl:element>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Which gives as output

. . .

<contrib-group>
        <contrib contrib-type="author">
                <name>
                        <surname>Franzke</surname>
                        <given-names>Christian L. E.</given-names>
                </name>
                <xref ref-type="aff" rid="aff2 aff3"/>
        </contrib>
        <aff id="aff2">Meteorological Institute and Center for Earth System Research and Sustainability 
(CEN), <institution>University of Hamburg</institution>, <country>Germany</country></aff>
        <aff id="aff3">Department of Cheddar, <institution>University of Curds and 
Whey</institution>, <country>Land of Cheese</country></aff>
</contrib-group>

. . .

But in cases of more than one <aff> in a <contrib-group>, instead of

        <xref ref-type="aff" rid="aff2 aff3"/>

it turns out the engineers really want

        <xref ref-type="aff" rid="aff2"/><xref ref-type="aff" rid="aff3"/>

Do I need to use a "for-each" to do this? I was beginning to think I was halfway clever 
when I figured out I didn't need a "for-each" to get the initial .xsl to work, but maybe 
not so clever after all.

You can use for-each select="parent::contrib-group/aff/@id" or
  <xsl:apply-templates select="parent::contrib-group/aff/@id" mode="ref"/>

and then

<xsl:template match="aff/@id" mode="ref">
  <xref ref-type="aff" rif="."/>

Incidental question: I have the version as 2.0 because, well, that was the 
version on the identity template I copied from wherever. I didn't see any 
reason for it to be 2.0, however, and 1.0 would be easier because you can run 
1.0 in .NET without additional software. But, when I changed the version to 
1.0, it ran fine but only gave the first @rid value, i.e.,

<xref ref-type="aff" rid="aff2"/>

Why?

With XSLT 1.0, xsl:value-of select="parent::contrib-group/aff/@id" outputs only the value of the first selected node because it is defined that way in XSLT 1.0 (https://www.w3.org/TR/xslt#value-of says to convert the node-set to a string and https://www.w3.org/TR/xpath/#function-string defines the string value of a node-set to be the string value of the first node). And XSLT 2.0 processors supporting backwards compatibility (like Saxon 9) are required to emulate that XSLT/XPath 1.0 behaviour (https://www.w3.org/TR/xslt20/#backwards, https://www.w3.org/TR/xslt20/#value-of "Special rules apply when backwards compatible behavior is enabled for the instruction. If no separator attribute is present, and if the select attribute is present, then all items in the atomized result sequence other than the first are ignored.").

--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>