How to parse nested tags using XSLT in sequence?

血红的双手。 提交于 2019-12-12 07:22:52

问题


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?


回答1:


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.




回答2:


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



来源:https://stackoverflow.com/questions/7763583/how-to-parse-nested-tags-using-xslt-in-sequence

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!