合并相似的节点并删除重复项

时间:2013-09-24 20:19:07

标签: xml xslt merge xslt-1.0 xslt-2.0

我正在寻找一种方法:

  1. 合并名称或值相似的节点。
  2. 合并后,删除节点的重复属性。
  3. 如果两个属性具有不同的值,则第一个属性的值必须替换为已合并的第二个属性的值。
  4. 以下是示例代码:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <books>
        <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh"> 
            <attribute name="BName">abc123</attribute> 
            <depends optional-attribute-name="Bookname">mypersonnelbook</depends> 
            <attribute name="Type1">book.type1.name</attribute> 
            <attribute name="Properties"> 
                bookname=book1
                price=100 
            </attribute> 
        </mbean>
        <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh"> 
            <attribute name="BName">abc123</attribute> 
            <depends optional-attribute-name="Bookname">mypersonnelbook</depends> 
            <attribute name="Type2">book.type2.name</attribute>         
            <attribute name="Properties"> 
                bookname=book1
                price=100 
            </attribute> 
        </mbean>
        <us-country-factory>
            <jndi-name>books/props/Classic</jndi-name> 
            <file-name>book1</file-name> 
            <state-location>central.wharehouse</state-location> 
            <store-property name="store" type="java.lang.String">abc</store-property> 
            <store-property name="storetype" type="java.lang.String">1223</store-property> 
            <store-property name="storelocation" type="java.lang.String">defsdgfd</store-property> 
            <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property> 
        </us-country-factory>
        <us-country-factory>
            <jndi-name>books/props/Classic</jndi-name> 
            <file-name>book1</file-name> 
            <state-location>central.wharehouse</state-location> 
            <store-property name="store" type="java.lang.String">defghij</store-property> 
            <store-property name="storetype" type="java.lang.String">1223</store-property> 
            <store-property name="storelocation" type="java.lang.String">32das</store-property> 
            <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property> 
            <store-property name="storeratings" type="java.lang.String">5</store-property> 
    

    我看的输出是:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <books>
        <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh"> 
            <attribute name="BName">abc123</attribute> 
            <depends optional-attribute-name="Bookname">mypersonnelbook</depends> 
            <attribute name="Type1">book.type1.name</attribute> 
            <attribute name="Type2">book.type2.name</attribute> 
            <attribute name="Properties"> 
                bookname=book1
                price=100 
            </attribute> 
        </mbean>
        <us-country-factory>
            <jndi-name>books/props/Classic</jndi-name> 
            <file-name>book1</file-name> 
            <state-location>central.wharehouse</state-location> 
            <store-property name="store" type="java.lang.String">defghij</store-property>  
            <store-property name="storetype" type="java.lang.String">1223</store-property> 
            <store-property name="storelocation" type="java.lang.String">32das</store-property> 
            <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property> 
            <store-property name="storeratings" type="java.lang.String">5</store-property> 
        </us-country-factory>   
    </books>
    
            </us-country-factory>   
        </books>
    

    这是我尝试过的xsl文件:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:key name="mbeanName" match="//mbean/@name" use="."/>
        <xsl:key name="mbeanCount" match="//mbean[generate-id(@name) = generate-id(key('mbeanName', @name)[1])]" use="count(.)"/>
        <xsl:key name="us-country-factoryName" match="//us-country-factory[jndi-name/text()]" use="."/>
        <xsl:key name="us-country-factoryCount" match="/us-country-factory[generate-id(jndi-name/text()) = generate-id(key('us-country-factoryName', jndi-name/text())[1])]" use="count(.)"/>
    
     <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="mbean[count(. | key('mbeanCount', /mbean/@name))]" />
        <xsl:template match="mbean[count(. | key('us-country-factoryCount', us-country-factory[jndi-name/text()]))]" />
    </xsl:stylesheet>
    

1 个答案:

答案 0 :(得分:1)

由于您已将问题标记为XSLT 2.0,我建议尝试使用for-each-group而不是密钥。这是一个示例样式表:

<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/> 

<xsl:template match="books">
  <xsl:copy>
    <xsl:for-each-group select="mbean" group-by="@name">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each-group select="current-group()/*" group-by="node-name(.)">
          <xsl:for-each-group select="current-group()" group-by="@*">
            <xsl:copy>
              <xsl:copy-of select="@*, current-group()[last()]/node()"/>
            </xsl:copy>
          </xsl:for-each-group>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:for-each-group>
    <xsl:for-each-group select="us-country-factory" group-by="jndi-name">
      <xsl:copy>
        <xsl:copy-of select="@*, *[not(@*)]"/>
        <xsl:for-each-group select="current-group()/*[@*]" group-by="string-join(@*, '|')">
          <xsl:copy>
            <xsl:copy-of select="@*, current-group()[last()]/node()"/>
          </xsl:copy>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

改变

<books>
    <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh"> 
        <attribute name="BName">abc123</attribute> 
        <depends optional-attribute-name="Bookname">mypersonnelbook</depends> 
        <attribute name="Type1">book.type1.name</attribute> 
        <attribute name="Properties"> 
            bookname=book1
            price=100 
        </attribute> 
    </mbean>
    <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh"> 
        <attribute name="BName">abc123</attribute> 
        <depends optional-attribute-name="Bookname">mypersonnelbook</depends> 
        <attribute name="Type2">book.type2.name</attribute>         
        <attribute name="Properties"> 
            bookname=book1
            price=100 
        </attribute> 
    </mbean>
    <us-country-factory>
        <jndi-name>books/props/Classic</jndi-name> 
        <file-name>book1</file-name> 
        <state-location>central.wharehouse</state-location> 
        <store-property name="store" type="java.lang.String">abc</store-property> 
        <store-property name="storetype" type="java.lang.String">1223</store-property> 
        <store-property name="storelocation" type="java.lang.String">defsdgfd</store-property> 
        <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property> 
    </us-country-factory>
    <us-country-factory>
        <jndi-name>books/props/Classic</jndi-name> 
        <file-name>book1</file-name> 
        <state-location>central.wharehouse</state-location> 
        <store-property name="store" type="java.lang.String">defghij</store-property> 
        <store-property name="storetype" type="java.lang.String">1223</store-property> 
        <store-property name="storelocation" type="java.lang.String">32das</store-property> 
        <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property> 
        <store-property name="storeratings" type="java.lang.String">5</store-property> 
    </us-country-factory>
</books>

<books>
   <mbean code="abc.def.ghi" name="com.booking.props:name=abcdefgh">
      <attribute name="BName">abc123</attribute>
      <attribute name="Type1">book.type1.name</attribute>
      <attribute name="Properties">
            bookname=book1
            price=100
        </attribute>
      <attribute name="Type2">book.type2.name</attribute>
      <depends optional-attribute-name="Bookname">mypersonnelbook</depends>
   </mbean>
   <us-country-factory>
      <jndi-name>books/props/Classic</jndi-name>
      <file-name>book1</file-name>
      <state-location>central.wharehouse</state-location>
      <store-property name="store" type="java.lang.String">defghij</store-property>
      <store-property name="storetype" type="java.lang.String">1223</store-property>
      <store-property name="storelocation" type="java.lang.String">32das</store-property>
      <store-property name="storecategory" type="java.lang.String">hjtbngb</store-property>
      <store-property name="storeratings" type="java.lang.String">5</store-property>
   </us-country-factory>
</books>

我意识到这不是一个完整的解决方案,但它应该让您了解如何使用XSLT 2.0解决问题。您将精确定义“名称或值相似的合并节点”对于您的不同元素类型的含义,然后使用for-each-groups实现它。

以下是一些解释的尝试,代码

<xsl:for-each-group select="mbean" group-by="@name">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:for-each-group select="current-group()/*" group-by="node-name(.)">
      <xsl:for-each-group select="current-group()" group-by="@*">
        <xsl:copy>
          <xsl:copy-of select="@*, current-group()[last()]/node()"/>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:for-each-group>

mbean属性对name元素进行分组,然后对组中的第一个元素进行浅层复制(因为您要消除重复),然后复制任何属性。此外,内部for-each-group按名称对mbean组中的所有子元素进行分组(因此我们将所有attribute元素分组,然后将所有depends元素分组),然后按其属性进行分组值。这是一种简化,因为输入只有这些元素的一个属性。因此,在内部for-each-groups内,我们现在有一组例如attribute name="BName"元素。我们对组中的第一个元素(组中的上下文节点)进行浅层复制,然后复制其属性,但复制组中最后一项的内容。