XSLT - To keep parent attribute value only on firs

2019-08-30 07:43发布

问题:

Input xml is like as,

<figure id="c035_f001" counter="yes">
<legend><para>The TLIF is indicated to aid reduction of spondylolisthesis and restore disc height, which decompresses the foramina.</para></legend>
<subfigure>
<graphic position="center" fileref="images/9781626230408_c035_f001.jpg"/>
</subfigure>
<subfigure>
<graphic position="center" fileref="images/9781626230408_c035_f001a.jpg"/>
</subfigure>
</figure>

Output should be,

<figure counter="yes">
<legend><para>The TLIF is indicated to aid reduction of spondylolisthesis and restore disc height, which decompresses the foramina.</para></legend>
<subfigure id="c035_f001">
<graphic position="center" fileref="images/9781626230408_c035_f001.jpg"/>
</subfigure>
<subfigure>
<graphic position="center" fileref="images/9781626230408_c035_f001a.jpg"/>
</subfigure>
</figure>

We wrote XSLT like as shown below.

 <xsl:template match="subfigure">
 <xsl:variable name="fig" select="parent::figure/@id"></xsl:variable>
 <xsl:choose>
 <xsl:when test="subfigure[not[@id]]">
 <xsl:if test="subfigure[not[@id]]">
 <xsl:copy>    
 <xsl:apply-templates select="@*"/>
 <xsl:attribute name="id">
 <xsl:value-of select="$fig"></xsl:value-of>
 </xsl:attribute>
 <xsl:apply-templates select="node()"/>
 </xsl:copy>            
 </xsl:if>
 </xsl:when>
 <xsl:otherwise>
 <xsl:copy>                
 <xsl:apply-templates select="node() | @*"/>
 </xsl:copy>
 </xsl:otherwise>
 </xsl:choose>        
 </xsl:template>

While using above xslt, we are getting output as,

<figure counter="yes">
<legend><para>The TLIF is indicated to aid reduction of spondylolisthesis and restore disc height, which decompresses the foramina.</para></legend>
<subfigure id="c035_f001">
<graphic position="center" fileref="images/9781626230408_c035_f001.jpg"/>
</subfigure>
<subfigure id="c035_f001">
<graphic position="center" fileref="images/9781626230408_c035_f001a.jpg"/>
</subfigure>
</figure>

The "id" repeating on both the "subfigure" elements. But we require only on first position. Could you please guide us.

回答1:

Consider to move the general identity transformation into a template of its own:

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

then add templates for those nodes needing special treatment where you make sure you put all conditions in match patterns e.g.

<xsl:template match="figure[@id]/subfigure[1][not(@id)]">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:copy-of select="../@id"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>


回答2:

Some preliminals:

(1) The provided XSLT does not produce the demonstrated XML output, but only two <subfigure> elements.

(2) not[] refers to an element <not>, but you actually mean not() to negate the argument.

(3) I understand that you need to "move" @id from <figure> to <subfigure>. Everything else remains as it is, right?

(4) To accomplish this task, you just need an identity copy with some exceptions:

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

<!-- remove @id from figure (but only when it contains subfigures) -->
<xsl:template match="figure[subfigure]/@id"/>

<!-- insert @id into first subfigure from superordinate figure -->
<xsl:template match="subfigure[not(@id)][1]">
    <subfigure>
        <xsl:copy-of select="ancestor::figure[1]/@id"/>
        <!-- do not forget to copy possible other attributes -->
        <xsl:apply-templates select="@* | node()"/>
    </subfigure>
</xsl:template>

Hope it helps!



标签: xml xslt