XSLT匹配节点和后代

时间:2017-01-05 12:12:52

标签: xml xslt

我有以下XML示例:

<root>
    <Customer>
        <Name/>
        <Address>
            <AddressLine1/>
            <AddressLine2/>
            <AddressLine3/>
        </Address>
    </Customer>
    <Provider>
        <Region>
            <County/>
        </Region>
        <HeadOffice>
            <Address>
                <Line1/>
                <Line2/>
                <Postcode>
                    <Sector/>
                </Postcode>
            </Address>
        </HeadOffice>
    </Provider>
</root>

我想为Address元素和所有后代元素添加一个属性,以便我的输出看起来像这样:

<root>
    <Customer>
        <Name/>
        <Address defer="true">
            <AddressLine1 defer="true"/>
            <AddressLine2 defer="true"/>
            <AddressLine3 defer="true"/>
        </Address>
    </Customer>
    <Provider>
        <Region>
            <County/>
        </Region>
        <HeadOffice>
            <Address defer="true">
                <Line1 defer="true"/>
                <Line2 defer="true"/>
                <Postcode defer="true">
                    <Sector defer="true"/>
                </Postcode>
            </Address>
        </HeadOffice>
    </Provider>
</root>

Address元素可能有不同的父元素和不同的后代,但我总是希望将属性添加到它及其所有后代。

我有这个XSLT来完成这项工作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Address|Address//*">
        <xsl:element name="{local-name()}">
        <xsl:attribute name="defer">true</xsl:attribute>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

但是<xsl:template match="Address|Address//*">感觉很笨拙。

是否有一种更好/更优雅的方式来匹配元素及其所有后代,或者这是最好的方法吗?

2 个答案:

答案 0 :(得分:2)

您的模式match="Address|Address//*"是表达任何Address元素和Address元素的任何可能后代元素的匹配的正确方法。我不明白为什么它笨重或不优雅。您可以在我的视图中将<xsl:element name="{local-name()}">更改为<xsl:copy>,以便更优雅地复制匹配的元素,但当然优雅是个人判断。

答案 1 :(得分:1)

有关XSLT性能的规则之一是避免在XPath中使用“//”。 因此,如果性能是一个问题,您可以使用以下XSL:

<esc>:w data/temp.txt

另请注意,第二个模板中的<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[ancestor-or-self::Address]"> <xsl:element name="{local-name()}"> <xsl:attribute name="defer">true</xsl:attribute> <xsl:apply-templates select="node()|@*"/> </xsl:element> </xsl:template> </xsl:stylesheet> 具有apply-templates属性。 如果省略它,您将丢失其他属性(如果有)。