How to parse nested tags using XSLT in sequence?

2019-02-15 16:47发布

I have below scenario for my XML.

<content>
  <para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para>
</content>

I want to parse it like below

<content>
<p>text-1 <b>text-2</b> text-3</p>
</content>

I have created my XSLT as below

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="ISO-8859-1" indent="no"/>

<xsl:template name="para">
    <p>
        <xsl:value-of select="text()" disable-output-escaping="yes"/>
        <xsl:for-each select="child::*">
            <xsl:if test="name()='emphasis'">
                <xsl:call-template name="emphasis"/>
            </xsl:if>
        </xsl:for-each>

    </p>
</xsl:template>
<xsl:template name="emphasis">
    <xsl:if test="attribute::type = 'bold'">
        <b>
            <xsl:value-of select="text()" disable-output-escaping="yes"/>
        </b>
    </xsl:if>
</xsl:template>

<xsl:template match="/">
    <content>
        <xsl:for-each select="content/child::*">
            <xsl:if test="name()='para'">
                <xsl:call-template name="para"/>
            </xsl:if>
        </xsl:for-each>
    </content>
</xsl:template>
</xsl:stylesheet>

XSLT provided above is generating output like below

<content>
 <p>text-1  text-3<b>text-2 </b></p>
</content>

Please guide me with your suggestions, how can I get my desire output?

2条回答
爷的心禁止访问
2楼-- · 2019-02-15 17:10

To do this, you just need to extend the standard Identity Transform with special cases for matching your para and emphasis elements. For example, for para elements you would the following to replace para with p and then continue matching all the child nodes

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

So, given the following XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

    <!-- This is the Identity Transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- Replace para with p -->
    <xsl:template match="para">
        <p>
            <xsl:apply-templates select="@*|node()"/>
        </p>
    </xsl:template>

    <!-- Replace emphasis with b -->
    <xsl:template match="emphasis[@type='bold']">
        <b>
            <xsl:apply-templates select="node()"/>
        </b>
    </xsl:template>
</xsl:stylesheet>

When applied to the following input XML

<content> 
  <para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para> 
</content> 

The following is output

<content>
    <p>text-1 <b>text-2</b> text-3</p>
</content>

You should be able to see how easy it is to extend to other cases should you input XML have more tags to transform.

查看更多
▲ chillily
3楼-- · 2019-02-15 17:31

do it like this ;)

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

    <xsl:template match="content">
        <content><xsl:apply-templates select="para" /></content>
    </xsl:template>

    <xsl:template match="emphasis [@type='bold']">
        <b><xsl:value-of select="." /></b>
    </xsl:template>

</xsl:stylesheet>

when you do it like this the default template will catch text-1 and text-3

查看更多
登录 后发表回答