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

发布于 2024-11-08 04:35:39 字数 3176 浏览 1 评论 0原文

我有以下简化的 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>

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

我想出了这个到目前为止效果很好的解决方案:

<?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>

如果有 元素,则输出是这样的:

<?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>

如果只有 并且没有映射被中止。

现在我有两个问题:

- 我对 元素的测试是否可靠:test="not(ExportData/DataSet/Tables/Table/Rows/node())"?

-我使用 创建 项,而不是 代码>构造。我的 XPath 表达式还可以吗?或者我可以改进它们吗?

I have the following simplified XML structure:

<?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>

I have to check if <R> elements exist or not. If no <R> elements exist the mapping has to be aborted, otherwise a <Line> element per <R> needs to be created.

I came up with this solution which works perfectly so far:

<?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>

If there are <R> elements the output is this:

<?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>

If there is just <Rows/> and no <R>s the mapping is aborted.

Now I have two questions:

-Is my test for <R> elements robust: test="not(ExportData/DataSet/Tables/Table/Rows/node())" ?

-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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

后eg是否自 2024-11-15 04:35:39

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

好吧,您是否希望它在没有 R 元素时失败,或者在 Rows 没有子 node() 时失败,这将包括任何元素(不仅仅是R)、text()comment()processing - 指令()?

如果您确实想验证是否至少有一个 R 元素是 Rows 的子元素,您应该将测试标准调整得更具体:< /strong>

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

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

我正在使用 ;创建<线>项目而不是 
构造。 
我的 XPath 表达式还可以吗?或者我可以改进它们吗?

您可以删除根节点模板内的 条件逻辑,并将该逻辑移至不包含的 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>

Is my test for elements robust: test="not(ExportData/DataSet/Tables/Table/Rows/node())"
?

Well, do you want it to fail if there are no R elements, or fail if Rows does not have a child node(), which would include any element (not just R), text(), comment() or processing-instruction()?

If you really want to verify that there is at least one R element that is a child of Rows, you should adjust the test criteria to be more specific:

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

Otherwise, it may pass that test and continue processing and not generate the content you want.

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?

You could get rid of the <xsl:if> conditional logic inside of your template for the root node and move that logic into a template for Rows that don't contain R children. Putting logic into xsl:template @match criteria makes it easier for XSLT processors to optimize, which can lead to performance gains.

<?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>
半枫 2024-11-15 04:35:39

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

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

This will check whether R node has child element:

<xsl:if test="R">
   <!--What you want to do here-->
</xsl:if>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文