如何使用xslt匹配具有公共属性和不同属性的节点

时间:2018-02-15 23:32:02

标签: xslt xpath xslt-1.0

我有一个类似下面的XML文件。我需要做的是在以下情况下为每个<TOKEN>节点添加一个带有<MULTIPLE TYPE='YES'>节点的标志:

  1. 存在多个具有相同<TOKEN>
  2. @BEGIN-@END
  3. 至少有一个<TOKEN> @TEXT与其他@BEGIN-@END不同
  4. xml代码如下:

        <?xml version="1.0" encoding="UTF-8"?>
        <ALL>
            <RECORD TEMPLATE="PRODUCTS" DB="0">
                <FIELD NAME="PRODUCT" BASE="AST" >          
                    <TOKEN  TEXT="AST" BEGIN="0" END="100"/>
                </FIELD>
            </RECORD>
            <RECORD TEMPLATE="PRODUCTS" DB="1" >
                <FIELD NAME="PRODUCT" BASE="BUC" >
                    <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                    <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                    <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                    <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                    <TOKEN TEXT="BUC" BEGIN="102" END="133"/>
                    <TOKEN TEXT="BUC" BEGIN="102" END="133"/>
                </FIELD>
            </RECORD>
            <RECORD TEMPLATE="PRODUCTS" DB="1" >
                <FIELD NAME="PRODUCT" BASE="BUC" >
                    <TOKEN TEXT="ART" BEGIN="300" END="450"/>
                    <TOKEN TEXT="ART" BEGIN="300" END="450"/>
                </FIELD>
            </RECORD>
    
        </ALL>
    

    所需的输出如下:

    <ALL>
        <RECORD DB="0" TEMPLATE="PRODUCTS">
            <FIELD BASE="AST" NAME="PRODUCT">           
                 <MULTIPLE TYPE="YES"/>
                 <TOKEN BEGIN="0" END="100" TEXT="AST"/>
            </FIELD>
        </RECORD>
        <RECORD DB="1" TEMPLATE="PRODUCTS">
            <FIELD BASE="BUC" NAME="PRODUCT">
                <MULTIPLE TYPE="YES"/>
                <TOKEN BEGIN="0" END="100" TEXT="BUC"/>
    
                <MULTIPLE TYPE="YES"/>
                <TOKEN BEGIN="0" END="100" TEXT="BUC"/>
    
                <MULTIPLE TYPE="YES"/>
                <TOKEN BEGIN="0" END="100" TEXT="BUC"/>
    
                <MULTIPLE TYPE="YES"/>
                <TOKEN BEGIN="0" END="100" TEXT="BUC"/>
    
                <TOKEN BEGIN="102" END="133" TEXT="BUC"/>
    
                <TOKEN BEGIN="102" END="133" TEXT="BUC"/>
            </FIELD>
        </RECORD>
        <RECORD DB="1" TEMPLATE="PRODUCTS">
            <FIELD BASE="BUC" NAME="PRODUCT">
    
                <TOKEN BEGIN="300" END="450" TEXT="ART"/>
    
                <TOKEN BEGIN="300" END="450" TEXT="ART"/>
            </FIELD>
        </RECORD>
    </ALL>
    

    我尝试使用以下xslt,并尝试匹配@BEGIN-@END@TEXT,但它没有效果。

      <?xml version="1.0" encoding="UTF-8"?>                        
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output encoding="UTF-8" cdata-section-elements="DOCUMENT" method="xml" indent="yes" omit-xml-declaration="no" />
    
              <xsl:key name="token" match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN" use="concat(@BEGIN, '|', @END)"/>
              <xsl:key name="text" match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN" use="@TEXT"/>
    
          <xsl:template match="@*|node()" name="identity">
            <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
          </xsl:template>
    
          <xsl:template match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN  [key('token', concat(@BEGIN, '|', @END))[2]] [(key('word', @TEXT)[2])] ">
            <xsl:element name="MULTIPLE">
                <xsl:attribute name="TYPE">YES</xsl:attribute>
            </xsl:element>  
            <xsl:call-template name="identity" />
          </xsl:template>
    
        </xsl:stylesheet>
    

    从代码的[(key('word', @TEXT)[2])]部分上方删除xslt,添加<MULTIPLE TYPE='YES'>节点,但在每个<TOKEN>上添加@BEGIN-@END,不检查是否存在@TEXT节点与其他节点不同。

1 个答案:

答案 0 :(得分:0)

你能检查一下:

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

    <xsl:output encoding="UTF-8" method="xml" indent="yes" omit-xml-declaration="no" />

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

    <xsl:template match="TOKEN">
        <xsl:variable name="current" select="concat(@BEGIN,@END)"/>
        <xsl:variable name="text" select="@TEXT"/>
        <xsl:for-each select="ancestor::RECORD/following-sibling::RECORD/FIELD/TOKEN|ancestor::RECORD/preceding-sibling::RECORD/FIELD/TOKEN">
            <xsl:if test="(concat(@BEGIN,@END) = $current) and (@TEXT!=$text)">
                <MULTIPLE TYPE="YES"/>
            </xsl:if>
        </xsl:for-each>
        <TOKEN>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </TOKEN>
    </xsl:template>

</xsl:stylesheet>