当前位置 : 主页 > 网页制作 > xml >

从XML分组具有相同值的节点

来源:互联网 收集:自由互联 发布时间:2021-06-13
嗨,我是Xslt / Xml的新手. 我有这样的XML: entry attribute1A/attribute1 attribute2B/attribute2/entryentry attribute1A/attribute1 attribute2B/attribute2/entryentry attribute1C/attribute1 attribute2D/attribute2/entryentry attribute1
嗨,我是Xslt / Xml的新手.

我有这样的XML:

<entry>
 <attribute1>A</attribute1>
 <attribute2>B</attribute2>
</entry>
<entry>
 <attribute1>A</attribute1>
 <attribute2>B</attribute2>
</entry>
<entry>
 <attribute1>C</attribute1>
 <attribute2>D</attribute2>
</entry>
<entry>
 <attribute1>E</attribute1>
 <attribute2>F</attribute2>
</entry>
...

我需要表输出:

一个

Attribute1 Attribute2 Qty
   A           B       2
   C           D       1
   E           F       1

我需要你的帮助,我不知道如何计算唯一条目并将其显示为表中的一个.

我使用的是XSLT 1.0版

I.简单的XSLT 1.0转换:

<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="kEntryByChildren" match="entry" use="."/>

 <xsl:template match=
 "entry[not(generate-id() = generate-id(key('kEntryByChildren', .)[1]))]"/>

 <xsl:template match="entry">
  <tr>
   <xsl:apply-templates/>
   <td><xsl:value-of select="count(key('kEntryByChildren', .))"/></td>
  </tr>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:template match="/*">
   <table>
     <xsl:apply-templates/>
   </table>
 </xsl:template>
</xsl:stylesheet>

当应用于提供的XML时(片段被包装到单个顶部元素以获得格式良好的XML文档):

<t>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>B</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>B</attribute2>
    </entry>
    <entry>
        <attribute1>C</attribute1>
        <attribute2>D</attribute2>
    </entry>
    <entry>
        <attribute1>E</attribute1>
        <attribute2>F</attribute2>
    </entry>
</t>

产生想要的,正确的结果:

<table>
   <tr>
      <td>A</td>
      <td>B</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

当应用于这个棘手的XML文档时(如果我们使用子级值的简单连接,我们会错误地断定前三个条目元素是“相同的”):

<t>
    <entry>
        <attribute1>AB</attribute1>
        <attribute2>C</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>BC</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>BC</attribute2>
    </entry>
    <entry>
        <attribute1>C</attribute1>
        <attribute2>D</attribute2>
    </entry>
    <entry>
        <attribute1>E</attribute1>
        <attribute2>F</attribute2>
    </entry>
</t>

产生了正确的结果:

<table>
   <tr>
      <td>AB</td>
      <td>C</td>
      <td>1</td>
   </tr>
   <tr>
      <td>A</td>
      <td>BC</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

说明:

正确使用Muenchian grouping method.

请注意:

>此解决方案不依赖于条目元素的子名称和子项数,因此可以应用于具有两个以上子项或具有未知事先名称的不同数量的子项的情况.
>这里我们假设所有子项的字符串值的串联仅在相同的子项具有相同值时才相同.

II.完整的XSLT 1.0解决方案:

如果无法保证上面的假设2.这是一个可能的XSLT 1.0解决方案:

<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:template match="entry">
  <xsl:variable name="vChildrenFp">
    <xsl:for-each select="*">
     <xsl:value-of select="concat(., '+')"/>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="vPrecedingSame">
    <xsl:for-each select="preceding-sibling::entry">
     <xsl:variable name="vthisFP">
       <xsl:for-each select="*">
         <xsl:value-of select="concat(., '+')"/>
       </xsl:for-each>
     </xsl:variable>

     <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:if test="not(string($vPrecedingSame))">
      <xsl:variable name="vFollowingSame">
        <xsl:for-each select="following-sibling::entry">
         <xsl:variable name="vthisFP">
           <xsl:for-each select="*">
             <xsl:value-of select="concat(., '+')"/>
           </xsl:for-each>
         </xsl:variable>

         <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if>
        </xsl:for-each>
      </xsl:variable>

      <tr>
       <xsl:apply-templates/>
       <td><xsl:value-of select="string-length($vFollowingSame)+1"/></td>
      </tr>
  </xsl:if>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:template match="/*">
   <table>
     <xsl:apply-templates/>
   </table>
 </xsl:template>
</xsl:stylesheet>

当应用于同一XML文档(上面)时,会产生相同的正确结果:

<table>
   <tr>
      <td>A</td>
      <td>B</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

说明:

>对于每个条目元素,我们生成其子元素的“指纹”(FP),并在其前一个兄弟条目元素没有相同子元素的指纹时处理该条目元素.
>“相同”条目元素的计数以类似的方式完成 – 对于具有相同子元素FP值的任何后续兄弟条目元素,我们输出单个字符(‘1’).总计数是如此生成的字符串(“1”)加1的字符串长度.

III. XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:my="my:my" exclude-result-prefixes="my xs">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:param name="pExoticString" select="'+'"/>

 <xsl:template match="/*">
   <table>
     <xsl:for-each-group select="entry" group-by="my:fingerprint(.)">
       <tr>
           <xsl:apply-templates/>
           <td><xsl:value-of select="count(current-group())"/></td>
       </tr>
     </xsl:for-each-group>
   </table>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:function name="my:fingerprint" as="xs:string">
  <xsl:param name="pParent" as="element()"/>

  <xsl:sequence select="string-join($pParent/*, $pExoticString)"/>
 </xsl:function>
</xsl:stylesheet>

这个简单的解决方案很容易处理复杂的情应用于最后一个XML文档时,会生成所需的正确结果:

<table>
   <tr>
            <td>AB</td>
            <td>C</td>
         <td>1</td>
   </tr>
   <tr>
            <td>A</td>
            <td>BC</td>
         <td>2</td>
   </tr>
   <tr>
            <td>C</td>
            <td>D</td>
         <td>1</td>
   </tr>
   <tr>
            <td>E</td>
            <td>F</td>
         <td>1</td>
   </tr>
</table>

说明:

正确使用xsl:for-each-group,xsl:function,current-group()string-join().

网友评论