質問

Can I use XSLT to transform the following XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<p>The chemical formula for water is H<sub>2</sub>O. The rest of this paragraph is not relevant.</p>
<p>Another paragraph without subscripts.</p>
</Root>

to this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<p><text>The chemical formula for water is H</text><sub>2</sub><text>O. The rest of this paragraph is not relevant.</text></p>
<p>Another paragraph without subscripts.</p>
</Root>

i.e. wrap the different parts of a p element that contains sub elements into text elements?

This is my XSLT so far:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="Root|p">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="p[child::*[name()='sub']]">
    <xsl:copy>
        <xsl:element name="text">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:copy>
</xsl:template>
<xsl:template match="sub">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

but that wraps the whole paragraph into a <text> element and doesn't divide it at the 2. How can I make it do what I want?


A little background information, if you're interested: I want to import the XML into Adobe InDesign, but if I only apply the character style sub to sub elements, the second half of the paragraph (starting at the O) will still be in subscript. I have to wrap the other bits in <text> in order for the formatting to be correct.

役に立ちましたか?

解決

Match on the text nodes:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

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


<xsl:template match="text()[following-sibling::node()[1][self::sub]]
                     | text()[preceding-sibling::node()[1][self::sub]]">
  <text>
    <xsl:value-of select="."/>
  </text>
</xsl:template>

</xsl:stylesheet>

Of course if you don't want that behaviour for all text nodes then edit the match pattern to say e.g. match="p/text()[following-sibling::node()[1][self::sub]] | p/text()[preceding-sibling::node()[1][self::sub]]".

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top