1

我正在寻找一种方法:

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

这是一个示例代码:

<?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>
4

1 回答 1

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-group 实现它。

这是一些解释的尝试,代码

<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-group 中,我们现在有一组 egattribute name="BName"元素。我们对组中的第一个元素(组中的上下文节点)进行浅拷贝,然后复制其属性但复制组中最后一项的内容。

于 2013-09-25T09:42:03.477 回答