使用xslt测试是否存在具有特定内容的节点

时间:2012-05-31 19:37:58

标签: xslt

我正在尝试使用XSLT合并来自两个单独的web.xml文件的元素。例如,如果正在合并web-1.xml和web-2.xml,并且我正在处理web-1.xml,我希望将web-2.xml中的所有元素添加到结果中,除了任何已经存在于web-1.xml中。

在XSLT表中,我使用以下方法加载了要将servlet合并到另一个文档中的文档:

<xsl:variable name="jandy" select="document('web-2.xml')"/>

然后我有以下规则:

<xsl:template match="webapp:web-app">
  <xsl:copy>
    <!--  Copy all of the existing content from the document being processed  -->
    <xsl:apply-templates/>      

    <!--  Merge any <servlet> elements that don't already exist into the result  -->        
    <xsl:for-each select="$jandy/webapp:web-app/webapp:servlet">
      <xsl:variable name="servlet-name"><xsl:value-of select="webapp:servlet-name"/></xsl:variable>

      <xsl:if test="not(/webapp:web-app/webapp:servlet/webapp:servlet-name[text() = $servlet-name])">
        <xsl:copy-of select="."/>
      </xsl:if>
    </xsl:for-each>

  </xsl:copy>

</xsl:template>

我遇到的问题是如果正确的话进行测试。使用上面的代码,测试总是计算为false,是否存在具有给定节点的servlet-name元素。我尝试了各种不同的测试,但没有运气。

相关文件位于http://www.cs.hope.edu/~mcfall/stackoverflow/web-1.xmlhttp://www.cs.hope.edu/~mcfall/stackoverflow/transform.xslt(第二个web-2.xml也可以,但StackOverflow不允许我发布三个链接)。

2 个答案:

答案 0 :(得分:0)

您的模板与来自webapp:webapp的XPATH web-1.xml匹配 如果您的xsl:if条件为/webapp:web-app/webapp:servlet/webapp:servlet-name[text() = $servlet-name],则表示您正在禁用绝对XPATH。尝试使用相对XPATH:

  <xsl:if test="not(webapp:servlet/webapp:servlet-name[text() = $servlet-name])">
    <xsl:copy-of select="."/>
  </xsl:if>

我没有检查过,所以你得试一试。

此外,如果您能提供web-1.xml和web-2.xml文件会更容易。

修改

以下XSLT合并了两个文件 - 当输入XML的两个位置存在相同类型的部分(如侦听器)时,会出现唯一的问题。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:webapp="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xpath-default-namespace="http://java.sun.com/xml/ns/javaee">

    <xsl:output indent="yes"/>
    <xsl:variable name="jandy" select="document('web-2.xml')"/>
    <xsl:template match="/">
        <xsl:element name="web-app">
            <xsl:for-each select="webapp:web-app/*[(name() != preceding-sibling::node()[1]/name()) or (position() = 1)]">
                <xsl:variable name="nodeName" select="./name()"/>
                <xsl:variable name="web1" as="node()*">
                    <xsl:sequence select="/webapp:web-app/*[name()=$nodeName]"/>
                </xsl:variable>
                <xsl:variable name="web2" as="node()*">
                    <xsl:sequence select="$jandy/webapp:web-app/*[name() = $nodeName]"/>
                </xsl:variable>
                <xsl:copy-of select="$web1" copy-namespaces="no"/>
                <xsl:for-each select="$web2">
                    <xsl:variable name="text" select="./*[1]/text()"/>
                    <xsl:if test="count($web1[*[1]/text() = $text]) = 0">
                        <xsl:copy-of select="." copy-namespaces="no"/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

在for-each循环之前为第一个文档提供锚点:

<xsl:variable name="var" select="."/>

然后,在你的if:

中使用它
<xsl:if test="not($var/webapp:servlet/webapp:servlet-name[text() = $servlet-name])">