I have the following XML input :
<?xml version="1.0" encoding="UTF-8"?>
<parent>
<para>
<emphasis>
<emphasis>
blah 0
<Xref ref="1"/>
blah 1
</emphasis>
</emphasis>
</para>
<para>
blah 2 <Xref ref="2"/> blah 3
</para>
</parent>
I would like to get the Xref
nodes outside the para nodes, no matter how deep they are.
Using the following XSLT 1.0 code:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()" priority="0">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="kPrecedingXref" match="node()[not(self::Xref)]" use="generate-id(following-sibling::Xref[1])"/>
<xsl:template match="para[Xref]" priority="1">
<xsl:apply-templates select="Xref"/>
<xsl:if test="count(Xref/following-sibling::node())>0">
<para>
<xsl:apply-templates select="Xref/following-sibling::node()[not(self::Xref) and not(following-sibling::Xref)]"/>
</para>
</xsl:if>
</xsl:template>
<xsl:template match="Xref" priority="1">
<xsl:if test="parent::para">
<para>
<xsl:apply-templates select="key('kPrecedingXref', generate-id())"/>
</para>
</xsl:if>
<toolRef><xsl:value-of select="@ref"/></toolRef>
</xsl:template>
<xsl:template match="emphasis[Xref]" priority="1">
<xsl:copy>
<xsl:apply-templates select="node()[following-sibling::Xref]" />
</xsl:copy>
<xsl:apply-templates select="Xref"/>
<xsl:copy>
<xsl:apply-templates select="node()[preceding-sibling::Xref]" />
</xsl:copy>
</xsl:template>
</xsl:transform>
that handles this but can only get the Xref
nodes outside of their direct parent node. How can I change this code to get this:
Wanted output
<parent>
<para>
<emphasis>
<emphasis>
blah 0
</emphasis>
</emphasis>
</para>
<toolRef>1</toolRef>
<para>
<emphasis>
<emphasis>
blah 1
</emphasis>
</emphasis>
</para>
<para>blah 2 </para>
<toolRef>2</toolRef>
<para> blah 3</para>
</parent>
Here's the full example code: http://xsltransform.net/nbiCsZM/4
Thanks to michael.hor257k and a lot of fiddling around, I finally found a solution to my problem.
Here's my working XSLT 1.0 code
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()" priority="0">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" priority="0" mode="EXTRACT_XREF">
<xsl:param name="i" select="0"/>
<xsl:if test="descendant-or-self::text()[count(preceding-sibling::Xref)=$i]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()" mode="EXTRACT_XREF">
<xsl:with-param name="i" select="$i"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="para[descendant::Xref]" priority="1">
<xsl:call-template name="recursive">
<xsl:with-param name="node" select="."/>
<xsl:with-param name="count" select="0"/>
<xsl:with-param name="limit" select="count(descendant::Xref)"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="recursive">
<xsl:param name="node"/>
<xsl:param name="count" select="0"/>
<xsl:param name="limit"/>
<xsl:if test="$count<=$limit">
<xsl:apply-templates select="$node" mode="EXTRACT_XREF">
<xsl:with-param name="i" select="$count"/>
</xsl:apply-templates>
<xsl:apply-templates select="$node/descendant::Xref[$count + 1]"/>
<xsl:call-template name="recursive">
<xsl:with-param name="node" select="$node"/>
<xsl:with-param name="count" select="$count + 1"/>
<xsl:with-param name="limit" select="$limit"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Xref" priority="1">
<toolRef>
<xsl:attribute name="ref">
<xsl:value-of select="@ref"/>
</xsl:attribute>
</toolRef>
</xsl:template>
</xsl:transform>
I alaso added some testing nodes that should be copied without changes, to test out the all possible cases:
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<parent>
<dontChangeThisNode></dontChangeThisNode>
<para>
<emphasis mode="bold">
<emphasis mode="underline">blah 0<Xref ref="1"/>blah 1<Xref ref="3"/> blah</emphasis>
</emphasis>
</para>
<dontChangeThisNodeEither>hop</dontChangeThisNodeEither>
<para>blah 2 <Xref ref="2"/> blah 3</para>
<para>blah 4</para>
</parent>
And finally, here's what this code transforms it to:
XML output
<?xml version="1.0" encoding="UTF-8"?>
<parent>
<dontChangeThisNode/>
<para>
<emphasis mode="bold">
<emphasis mode="underline">blah 0</emphasis>
</emphasis>
</para>
<toolRef ref="1"/>
<para>
<emphasis mode="bold">
<emphasis mode="underline">blah 1</emphasis>
</emphasis>
</para>
<toolRef ref="3"/>
<para>
<emphasis mode="bold">
<emphasis mode="underline"> blah</emphasis>
</emphasis>
</para>
<dontChangeThisNodeEither>hop</dontChangeThisNodeEither>
<para>blah 2 </para>
<toolRef ref="2"/>
<para> blah 3</para>
<para>blah 4</para>
</parent>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.