检查子节点是否存在并应用模板

时间:2011-05-20 10:42:58

标签: xslt

我有以下简化的XML结构:

<?xml version="1.0" encoding="UTF-8"?>
<ExportData>
<TransportHeader>
    <Timestamp>2011-01-16 06:00:33</Timestamp>
    <From>
        <Name>DynamicExport</Name>
        <Version>1.</Version>
    </From>
    <MessageId>d7b5c5b69a83</MessageId>
</TransportHeader>
<ExportConfig>
    <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
    <DecimalSymbol>.</DecimalSymbol>
</ExportConfig>
<DataSet> 
    <Tables>
        <Table>
            <RH>...</RH>
            <Rows>
                <R>Data1</R>
                <R>Data2</R>
                <R>Data3</R>
                <R>Data4</R>
                <R>Data5</R>
            </Rows>
        </Table>
    </Tables>
</DataSet>
</ExportData>

我必须检查是否存在<R>个元素。如果不存在<R>元素,则必须中止映射,否则需要创建每<Line><R>个元素。

我想出了这个迄今为止完美无缺的解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />

<!-- suppress nodes that are not matched -->
<xsl:template match="text() | @*">
    <xsl:apply-templates select="text() | @*"/>
</xsl:template>

<xsl:template match="/">
    <xsl:choose>
        <xsl:when test="not(ExportData/DataSet/Tables/Table/Rows/node())">
            <xsl:message terminate="yes">No line items</xsl:message>
        </xsl:when>
        <xsl:otherwise>
            <xsl:apply-templates/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="/ExportData/DataSet/Tables/Table/Rows">
    <INVOIC02>
        <!-- apply LINE ITEMS template -->
        <xsl:apply-templates select="R"/>
    </INVOIC02>
</xsl:template>

<!-- Template creating LINE ITEMS -->
<xsl:template match="R">

    <Line>
        <elements></elements>
    </Line>
</xsl:template>


</xsl:stylesheet>

如果有<R>个元素,则输出为:

<?xml version="1.0" encoding="ISO-8859-1"?>
<INVOIC02>
<Line>
    <elements/>
</Line>
<Line>
    <elements/>
</Line>
<Line>
    <elements/>
</Line>
<Line>
    <elements/>
</Line>
<Line>
    <elements/>
</Line>
</INVOIC02>

如果只有<Rows/>且没有<R>,则映射将被中止。

现在我有两个问题:

- 我对<R>元素的测试是否健全:test="not(ExportData/DataSet/Tables/Table/Rows/node())"

- 我使用<xsl:apply-templates>创建<Line>项而不是<xsl:for-each>构造。我的XPath表达式是否正常还是可以让它们变得更好?

感谢您对此提出的任何回复或建议。

祝你好运, 彼得

2 个答案:

答案 0 :(得分:5)

  

我对元素的测试是否健壮:test =“not(ExportData / DataSet / Tables / Table / Rows / node())”   ?

那么,如果没有R元素,您希望它失败吗?如果Rows没有子node(),则会失败,其中包括任何元素< / em>(不只是R),text()comment()processing-instruction()

如果您确实要验证至少有一个R元素是Rows的子元素,则应将测试条件调整为更具体:

test="not(ExportData/DataSet/Tables/Table/Rows/R)"

否则,它可能会通过该测试并继续处理,而不会生成您想要的内容。

I am using <xsl:apply-templates> to create the <Line> items instead of an 
<xsl:for-each> construct. 
Are my XPath expressions okay or could I make them better?

您可以删除模板中针对根节点的<xsl:if>条件逻辑,并将该逻辑移动到不包含Rows子项的R模板中。将逻辑放入xsl:template @match条件可以使XSLT处理器更容易优化,从而提高性能。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />

    <!-- suppress nodes that are not matched -->
    <xsl:template match="text() | @*">
        <xsl:apply-templates select="text() | @*"/>
    </xsl:template>

    <!--All Rows must contain an R.  
        If we encounter any that do not, terminate the transform -->
    <xsl:template match="/ExportData/DataSet/Tables/Table/Rows[not(R)]">
        <xsl:message terminate="yes">No line items</xsl:message>
    </xsl:template>

    <!--match for Rows that have R children -->
    <xsl:template match="/ExportData/DataSet/Tables/Table/Rows[R]">
        <INVOIC02>
            <!-- apply LINE ITEMS template -->
            <xsl:apply-templates select="R"/>
        </INVOIC02>
    </xsl:template>

    <!-- Template creating LINE ITEMS -->
    <xsl:template match="R">      
        <Line>
            <elements></elements>
        </Line>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

请检查

<xsl:if test="R">
   <!--What you want to do here-->
</xsl:if>

这将检查R节点是否具有子元素。

Buddhika