-2

I am wondering does the statement [@id=current()/@id] can only work if the id is integer for example:

<elem id="1">
<elem id="1">

But if I have:

<elem id="AAA">
<elem id="AAA">

It does not work.

My XSL where it fails:

<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"
                xmlns:tn="http://"
                exclude-result-prefixes="xsl xs fn tn">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*" />

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

 <xsl:template match="genre/*">
        <xsl:copy>
            <xsl:apply-templates select="@*" />

            <xsl:apply-templates select="
     book[@id=current()/@id][@action='extend']                             
         [not( preceding-sibling::book[@id=current()/@id][@action='borrow'])]" />

            <xsl:for-each-group
                select="book[@id=current()/@id][@action='borrow'] 
             |   
            book[@id=current()/@id][@action='extend']
                [preceding-sibling::book[@id=current()/@id][@action='borrow']]"
                group-starting-with="book[@action='borrow']">
                <xsl:for-each select="current-group()[1]">
                    <xsl:copy>   
                        <xsl:apply-templates select="@*" />
                        <xsl:call-template name="merge-books-deeply">    
                            <xsl:with-param name="books" select="current-group()" />
                            <xsl:with-param name="name-path" select="()" />
                        </xsl:call-template>
                    </xsl:copy>
                </xsl:for-each>     
            </xsl:for-each-group>

            <xsl:apply-templates select="                             
     node()[ not( self::book[@id=current()/@id][@action=('borrow','extend')])]" />

        </xsl:copy>
    </xsl:template>

    <xsl:function name="tn:children-on-path" as="element()*">
        <xsl:param name="base" as="element()*" />   
        <xsl:param name="path" as="xs:string*" />    
        <xsl:choose>
            <xsl:when test="fn:empty($base)">
                <xsl:sequence select="()" />
            </xsl:when>
            <xsl:when test="fn:empty($path)">
                <xsl:copy-of select="$base/*" />     
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="tn:children-on-path(
     $base/*[name()=$path[1]],         
     $path[position() ne 1])" /> 
            </xsl:otherwise>  
        </xsl:choose>
    </xsl:function>

    <xsl:template name="merge-books-deeply">
        <xsl:param name="books" as="element()*" />
        <xsl:param name="name-path" as="xs:string*" />
        <xsl:for-each-group
            select="tn:children-on-path($books,$name-path)"
            group-by="name()">                                             
            <xsl:for-each select="current-group()[last()]" >  
                <xsl:copy>
                    <xsl:apply-templates select="@*" />
                    <xsl:call-template name="merge-books-deeply"> 
                        <xsl:with-param name="books" select="$books" />
                        <xsl:with-param name="name-path" select="$name-path,name()" />
                    </xsl:call-template>
                    <xsl:apply-templates select="text()" />        
                </xsl:copy>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

input sample where it works:

<root> 
    <library id="L1">
        <genre id="a">
            <shelf1 id="1">                
                <book id="1" action="borrow">
                    <attributes>
                        <user>John</user>                    
                    </attributes>
                    <other1>y</other1>
                </book>  
                <book id="1" action="extend">
                    <attributes>
                        <user>Woo</user>           
                        <length>3</length>
                    </attributes>
                    <other2>y</other2>
                </book>  
                <book id="1" action="extend">
                    <attributes>
                        <length>2</length>
                        <condition>ok</condition>
                    </attributes>
                    <other3>y</other3>
                </book>
                <book id="2" action="extend">
                    <attributes>
                        <length>99</length>
                        <condition>not-ok</condition>
                    </attributes>
                    <other>y</other>
                </book>
            </shelf1>
            <shelf1 id="b">...
            </shelf1>

        </genre>
        <genre id="b">...
        </genre>
    </library>
</root>

If I change the id of the book to 1a:

<root> 
    <library id="L1">
        <genre id="a">
            <shelf1 id="1">                
                <book id="1a" action="borrow">
                    <attributes>
                        <user>John</user>                    
                    </attributes>
                    <other1>y</other1>
                </book>  
                <book id="1a" action="extend">
                    <attributes>
                        <user>Woo</user>           
                        <length>3</length>
                    </attributes>
                    <other2>y</other2>
                </book>  
                <book id="1a" action="extend">
                    <attributes>
                        <length>2</length>
                        <condition>ok</condition>
                    </attributes>
                    <other3>y</other3>
                </book>
                <book id="2" action="extend">
                    <attributes>
                        <length>99</length>
                        <condition>not-ok</condition>
                    </attributes>
                    <other>y</other>
                </book>
            </shelf1>
            <shelf1 id="b">...
            </shelf1>

        </genre>
        <genre id="b">...
        </genre>
    </library>
</root>

My Error Output: (it doesn't merge at all)

<root> 
    <library id="L1">
        <genre id="a">
            <shelf1 id="1">                
                <book id="a1" action="borrow">
                    <attributes>
                        <user>John</user>                    
                    </attributes>
                    <other1>y</other1>
                </book>  
                <book id="a1" action="extend">
                    <attributes>
                        <user>Woo</user>           
                        <length>3</length>
                    </attributes>
                    <other2>y</other2>
                </book>  
                <book id="a1" action="extend">
                    <attributes>
                        <length>2</length>
                        <condition>ok</condition>
                    </attributes>
                    <other3>y</other3>
                </book>
                <book id="2" action="extend">
                    <attributes>
                        <length>99</length>
                        <condition>not-ok</condition>
                    </attributes>
                    <other>y</other>
                </book>
            </shelf1>
            <shelf1 id="b">...
            </shelf1>

        </genre>
        <genre id="b">...
        </genre>
    </library>
</root>

Expected Output:

<root> 
    <library id="L1">
        <genre id="a">
            <shelf1 id="1">                
                <book id="1a" action="borrow">
                    <attributes>
                        <user>Woo</user>           
                        <length>2</length>
                        <condition>ok</condition>                  
                    </attributes>
                    <other1>y</other1>
                </book>  
                <book id="2" action="extend">
                    <attributes>
                        <length>99</length>
                        <condition>not-ok</condition>
                    </attributes>
                    <other>y</other>
                </book>
            </shelf1>
            <shelf1 id="b">...
            </shelf1>

        </genre>
        <genre id="b">...
        </genre>
    </library>
</root>

For every node with action=borrow followed by one or more node with action=extend

  • Merge it together to the node with action=borrow.

  • Merge the attributes children together such that it will have all the unique attributes from the siblings with the latest value.

  • leave other children unchanged

THe merging only happen with node that has the same id.

Thanks. Regards, John

4

2 回答 2

3

也许您遇到了上下文问题。比较应该有效。这是一个例子......

XML 输入

<tests>
    <test>
        <elem id="1"/>
        <elem id="1"/>
    </test>
    <test>
        <elem id="AAA"/>
        <elem id="AAA"/>
    </test>
    <test>
        <elem id="BBB"/>
        <elem id="CCC"/>
    </test>
    <test>
        <elem id="2"/>
        <elem id="3"/>
    </test>
</tests>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="elem[1]">
        <xsl:text>Comparing id </xsl:text>
        <xsl:value-of select="concat('&quot;',@id,'&quot;&#xA;')"/>
        <xsl:value-of select="concat('&#x9;',
            boolean(following-sibling::*[@id=current()/@id]),
            '&#xA;')"/>
    </xsl:template>

</xsl:stylesheet>

输出

Comparing id "1"
    true
Comparing id "AAA"
    true
Comparing id "BBB"
    false
Comparing id "2"
    false

编辑

在查看您更新的示例之后,它肯定看起来像一个上下文问题。看一下模板的开头:

<xsl:template match="genre/*">
        <xsl:copy>
            <xsl:apply-templates select="@*" />

            <xsl:apply-templates select="
     book[@id=current()/@id][@action='extend']                             
         [not( preceding-sibling::book[@id=current()/@id][@action='borrow'])]" />

注意匹配是genre/*; 这就是当前的情况。有了您的输入,这将是shelf1. 然后第二个的选择xsl:apply-templatesbook[@id=current()/@id]. 对我来说,这看起来像是在选择book它是否具有id等于的id属性shelf1。要对此进行测试,您还可以将 of 更改idshelf11a它可能会起作用。(这就是第一个示例有效的原因;idofshelf1bookmatch。

我现在无法测试这个理论,但我认为这就是比较不起作用的原因。(它正在工作,你只是没有比较你认为你正在比较的东西。)

于 2012-07-16T18:32:19.100 回答
1

字符串比较不需要显式的字符串转换。换句话说,它应该像你写的那样工作。这是一个例子:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="elem">
    <xsl:if test="count(../elem[@id=current()/@id]) &gt; 1">
      <xsl:value-of select="@id"/>: has dup
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

应用于此输入时:

<r>
    <elem id="AAA">one</elem>
    <elem id="AAA">two</elem>
    <elem id="ZZZ">three</elem>
</r>

产生以下输出:

AAA: has dup
AAA: has dup

XPath 规范

否则,如果至少一个要比较的对象是一个数字,则每个要比较的对象都被转换为一个数字,就好像通过应用 number 函数一样。否则,两个要比较的对象都被转换为字符串,就好像通过应用字符串函数一样。

于 2012-07-16T18:26:10.063 回答