在XPATH / XSL中使用“except”时的结构要求

时间:2013-05-24 15:19:52

标签: xslt xpath xslt-2.0 xpath-2.0 except

我在xpath中使用“except”时遇到了麻烦。这是问题代码的一大块。 (我试图尽可能地简化而不会模糊整个问题)。:

<!--First, create a variable containing some nodes that we want to filter out. 
 (I'm gathering elements that are missing child VALUE elements
 and whose child DOMAIN and VARIABLE elements only occur once
 in the parent list of elements.)
 I've confirmed that this part does generate the nodes I want,
 but maybe this is the incorrect result structure?-->

<xsl:variable name="badValues">
 <xsl:for-each select="$root/A[not(VALUE)]">
  <xsl:choose>
   <xsl:when test="count($root/A[DOMAIN=current()/DOMAIN and VARIABLE=current()/VARIABLE])=1">
    <xsl:copy-of select="."/>
   </xsl:when>
  </xsl:choose>
 </xsl:for-each>
</xsl:variable>

<!--Next Loop over the original nodes, minus those bad nodes.
 For some reason, this loops over all nodes and does not filter out the bad nodes.-->

<xsl:for-each select="$root/A except $badValues/A"> ...

1 个答案:

答案 0 :(得分:1)

如果您在不使用xsl:variable的情况下创建@select并且未使用@as指定类型,则会将变量创建为temporary tree

您希望创建一系列节点,以便在except运算符中进行比较时,它们会被“视为”相同的节点。您可以为as="node()*"指定xsl:variable并使用xsl:sequence代替xsl:copy-of来执行此操作:

<xsl:variable name="badValues" as="node()*">
    <xsl:for-each select="$root/A[not(VALUE)]">
        <xsl:choose>
            <xsl:when test="count($root/A[DOMAIN=current()/DOMAIN 
                                   and VARIABLE=current()/VARIABLE])=1">
                <xsl:sequence select="."/>
            </xsl:when>
        </xsl:choose>
    </xsl:for-each>
</xsl:variable>

或者,如果您使用@select并取消xsl:for-each它也可以。正如Martin Honnen建议的那样,您可以使用xsl:key并选择如下值:

 <xsl:key name="by-dom-and-var" match="A" use="concat(DOMAIN, '|', VARIABLE)"/>

然后将badValues更改为:

<xsl:variable name="badValues" 
     select="$root/A[not(VALUE)]
                    [count(key('by-dom-and-var', 
                               concat(DOMAIN, '|', VARIABLE))/VARIABLE) = 1]"/>>

通过执行此样式表迭代项目时,可以使用generate-id()函数查看节点标识的差异:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:template match="/">
    <xsl:variable name="root" select="*" as="item()*"/>       
    <xsl:variable name="originalBadValues">
        <xsl:for-each select="$root/A[not(VALUE)]">
            <xsl:choose>
                <xsl:when test="count($root/A[DOMAIN=current()/DOMAIN 
                                      and VARIABLE=current()/VARIABLE])=1">
                    <xsl:copy-of select="."/>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="badValues" as="node()*">
        <xsl:for-each select="$root/A[not(VALUE)]">
            <xsl:choose>
                <xsl:when test="count($root/A[DOMAIN=current()/DOMAIN 
                                      and VARIABLE=current()/VARIABLE])=1">
                    <xsl:sequence select="."/>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:variable>

        <!--These are the generated ID values of all the A elements-->
        <rootA>
            <xsl:value-of select="$root/A/generate-id()" 
                          separator=", "/>
        </rootA>
        <!--These are the generated ID values for 
            the original $badValues/A --> 
        <originalBadValues>
            <xsl:value-of select="$originalBadValues/A/generate-id()" 
                          separator=", " />
        </originalBadValues>
        <!--These are the generated ID values for 
            the correct selection of $badValues-->
        <badValues>
            <xsl:value-of select="$badValues/generate-id()" 
                          separator=", " />
        </badValues>
        <!--The generated ID values for the result of 
            the except operator filter-->
        <final>
            <xsl:value-of select="($root/A except $badValues)/generate-id()" 
                          separator=", "/>
        </final>
    </xsl:template>        
</xsl:stylesheet>

针对此XML文件执行:

<doc>
    <A>
        <VALUE>skip me</VALUE>
        <DOMAIN>a</DOMAIN>
        <VARIABLE>a</VARIABLE>
    </A>
    <A>
        <DOMAIN>a</DOMAIN>
        <VARIABLE>a</VARIABLE>
    </A>
    <A>
        <DOMAIN>b</DOMAIN>
        <VARIABLE>b</VARIABLE>
    </A>
    <A>
        <DOMAIN>c</DOMAIN>
        <VARIABLE>c</VARIABLE>
    </A>
    <A>
        <DOMAIN>a</DOMAIN>
        <VARIABLE>a</VARIABLE>
    </A>
</doc>

它产生以下输出:

<rootA>d1e3, d1e15, d1e24, d1e33, d1e42</rootA>
<originalBadValues>d2e1, d2e9</originalBadValues>
<badValues>d1e24, d1e33</badValues>
<final>d1e3, d1e15, d1e42</final>