xsl-list
[Top] [All Lists]

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

2017-03-23 14:59:31

On 23 Mar 2017, at 18:23, Charles O'Connor coconnor(_at_)ariessys(_dot_)com 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_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>

You could be a lot less verbose:

 <xsl:template match="//contrib[not(xref/@ref-type='aff')]">
       <xsl:copy>
           <xsl:apply-templates select="@* | node()"/>
           <xref ref-type="aff" id="{../aff/@id}"/>
       </xsl:copy>
   </xsl:template>




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?

Yes, you do:

<xsl:for-each select="../aff">
   <xref ref-type="aff" id="{@id}"/>
</xsl:for-each>

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?

Because in XSLT 1.0, xsl:value-of (and many other operations), if given a set 
of nodes as input, ignores all but the first node in the set.

Michael Kay
--~----------------------------------------------------------------
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>