使用XSLT添加必需的节点

时间:2015-05-19 14:41:55

标签: xslt xpath

我正面临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:if测试失败,说“当前项目是xs:string类型的产品。”

我尝试了相同的xsl:如果在for-each之外它似乎有用......我错过了什么?

1 个答案:

答案 0 :(得分:2)

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

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