使用 XSLT 添加强制节点

Posted

技术标签:

【中文标题】使用 XSLT 添加强制节点【英文标题】:Add mandatory nodes with XSLT 【发布时间】:2015-07-31 11:18:37 【问题描述】:

我正面临一个 xslt/xpath 问题,希望有人能提供帮助,简而言之,这就是我试图实现的目标。

我必须转换一个可能缺少某些节点的 XML 文档,这些缺少的节点在最终结果中是强制性的。我在 xsl:param 中有一组强制性节点名称。

基础文档是:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="TRANSFORM.xslt"?>
<BEGIN>
    <CLIENT>
        <NUMBER>0021732561</NUMBER>
        <NAME1>John</NAME1>
        <NAME2>Connor</NAME2>
    </CLIENT>

    <PRODUCTS>
        <PRODUCT_ID>12</PRODUCT_ID>
            <DESCRIPTION>blah blah</DESCRIPTION>
    </PRODUCTS>

    <PRODUCTS>
        <PRODUCT_ID>13</PRODUCT_ID>
            <DESCRIPTION>description ...</DESCRIPTION>
    </PRODUCTS>

    <OPTIONS>
            <OPTION_ID>1</OPTION_ID>
            <DESCRIPTION>blah blah blah ...</DESCRIPTION>
    </OPTIONS>

    <PROMOTIONS>
            <PROMOTION_ID>1</PROMOTION_ID>
            <DESCRIPTION>blah blah blah ...</DESCRIPTION>
    </PROMOTIONS>

</BEGIN>

这是目前的样式表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <xsl:param name="mandatoryNodes" as="xs:string*" select=" 'PRODUCTS', 'OPTIONS', 'PROMOTIONS' "/>

    <xsl:template match="/">
        <xsl:apply-templates select="child::node()"/>
    </xsl:template>

    <xsl:template match="node()">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="BEGIN">
        <xsl:element name="BEGIN">
            <xsl:for-each select="$mandatoryNodes">
                <!-- If there is no node with this name -->
                <xsl:if test="count(*[name() = 'current()']) = 0"> 
                    <xsl:element name="current()" />
                </xsl:if> 
            </xsl:for-each>
            <xsl:apply-templates select="child::node()"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

我尝试了 XML Spy 中的转换,xsl:iftest 失败说'当前项目是 xs:string 类型的产品。

我尝试了相同的 xsl:if 在 for-each 之外,它似乎可以工作......我错过了什么?

【问题讨论】:

【参考方案1】:

&lt;xsl:for-each select="$mandatoryNodes"&gt; 内部,上下文项是一个字符串,但您想访问主输入文档及其节点,因此您需要将该文档或模板的上下文节点存储在一个变量中并使用它,例如

<xsl:template match="BEGIN">
    <xsl:variable name="this" select="."/>
    <xsl:element name="BEGIN">
        <xsl:for-each select="$mandatoryNodes">
            <!-- If there is no child node of `BEGIN` with this name -->
            <xsl:if test="count($this/*[name() = current()]) = 0"> 
                <xsl:element name="current()" />
            </xsl:if> 
        </xsl:for-each>
        <xsl:apply-templates select="child::node()"/>
    </xsl:element>
</xsl:template>

【讨论】:

感谢您的直接回答!

以上是关于使用 XSLT 添加强制节点的主要内容,如果未能解决你的问题,请参考以下文章

我可以通过XSLT强制使用XML属性,具体取决于另一个属性的值吗?

D3 强制布局应在单击节点时添加节点和链接

向 Hobbelt 的“Group/Bundle Nodes”D3 强制布局示例中的节点添加标签?

如何在节点/角度/nginx应用程序上强制缓存过期

使用xslt和c#从中选择​​一个xml节点并根据其值添加更多节点[重复]

根据节点的旋转对节点应用强制