首页 > 解决方案 > XSLT 层次结构转换中的重复项

问题描述

我是论坛的新手,所以请原谅我的风格和语言不是英语的一些错误。我的问题是我有一个来自 db 上的选择的 xml 输出,我想通过 xslt 在分层结构上转换这个平面结构。我的 xslt 工作正常并正确执行层次结构,但存在复制所有项目并使其复制根元素的问题 这是 db 上 select 的 xml 输出:

<cdcDbSet xmlns="http://eos.mcr.com/cdc/anagrafica/ds">
   <cdcEntity>
      <idCdc>17</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>testGP</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>15</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Caserta</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>5</idCdc>
      <idCdcParent>2</idCdcParent>
      <cdcName>Progetti</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>16</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>testGP</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>18</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>testGPS</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>11</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>figlio</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>10</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>3</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>6</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>EOS</cdcName>
      <order>3</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>3</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Milano</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>7</idCdc>
      <idCdcParent>3</idCdcParent>
      <cdcName>l</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>14</idCdc>
      <idCdcParent>15</idCdcParent>
      <cdcName>testMOD</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>8</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>4</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Napoli</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
   </cdcEntity>
   <cdcEntity>
      <idCdc>9</idCdc>
      <idCdcParent>4</idCdcParent>
      <cdcName>cccc</cdcName>
      <order>6</order>
      <isUsed>false</isUsed>
   </cdcEntity>
</cdcDbSet>

这是 xslt:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nsc="http://eos.mcr.com/cdc/anagrafica/ds" version="1.0">
<xsl:key match="/nsc:cdcDbSet/nsc:cdcEntity" name="nodeChildren" use="nsc:idCdcParent"/>
<xsl:variable name="root" select="/nsc:cdcDbSet/nsc:cdcEntity/nsc:idCdcParent"/>
<xsl:template match="nsc:cdcDbSet">
    <cdcList xmlns="http://ws.apache.org/ns/synapse">
        <xsl:apply-templates select="nsc:cdcEntity[nsc:idCdcParent=$root]"/>
    </cdcList>
</xsl:template>
<xsl:template match="nsc:cdcEntity">
    <cdc xmlns="http://ws.apache.org/ns/synapse">
        <idCdc>
            <xsl:value-of select="nsc:idCdc"/>
        </idCdc>
        <idCdcParent>
            <xsl:value-of select="nsc:idCdcParent"/>
        </idCdcParent>
        <cdcName>
            <xsl:value-of select="nsc:cdcName"/>
        </cdcName>
        <order>
            <xsl:value-of select="nsc:order"/>
        </order>
        <isUsed>
            <xsl:value-of select="nsc:isUsed"/>
        </isUsed>
        <cdcList>
            <xsl:apply-templates select="key('nodeChildren',nsc:idCdc)"/>
        </cdcList>
    </cdc>
</xsl:template>
</xsl:stylesheet>

这是转换后的 xml:

<cdcList xmlns="http://ws.apache.org/ns/synapse"
         xmlns:nsc="http://eos.mcr.com/cdc/anagrafica/ds">
   <cdc>
      <idCdc>17</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>testGP</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>15</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Caserta</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>14</idCdc>
            <idCdcParent>15</idCdcParent>
            <cdcName>testMOD</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>5</idCdc>
      <idCdcParent>2</idCdcParent>
      <cdcName>Progetti</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>17</idCdc>
            <idCdcParent>5</idCdcParent>
            <cdcName>testGP</cdcName>
            <order>1</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>18</idCdc>
            <idCdcParent>5</idCdcParent>
            <cdcName>testGPS</cdcName>
            <order>2</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>6</idCdc>
            <idCdcParent>5</idCdcParent>
            <cdcName>EOS</cdcName>
            <order>3</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>16</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>testGP</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>18</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>testGPS</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>11</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>figlio</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>10</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>3</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>6</idCdc>
      <idCdcParent>5</idCdcParent>
      <cdcName>EOS</cdcName>
      <order>3</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>3</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Milano</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>7</idCdc>
            <idCdcParent>3</idCdcParent>
            <cdcName>l</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>7</idCdc>
      <idCdcParent>3</idCdcParent>
      <cdcName>l</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>14</idCdc>
      <idCdcParent>15</idCdcParent>
      <cdcName>testMOD</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>8</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>4</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Napoli</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>9</idCdc>
            <idCdcParent>4</idCdcParent>
            <cdcName>cccc</cdcName>
            <order>6</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>9</idCdc>
      <idCdcParent>4</idCdcParent>
      <cdcName>cccc</cdcName>
      <order>6</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>

如您所见,有些项目重复,我想将其删除。例如,idCdc=17 的项目 cdc 位于 cdcList 下,而 idCdc=5 的 cdc 下我尝试修改 xslt,但没有得到很好的结果。感谢大家尝试帮助我。

Ps:我希望看到这样的东西:

    <cdcList xmlns="http://ws.apache.org/ns/synapse" xmlns:nsc="http://eos.mcr.com/cdc/anagrafica/ds">
   <cdc>
      <idCdc>1</idCdc>
      <idCdcParent>0</idCdcParent>
      <cdcName>Roma</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>4</idCdc>
            <idCdcParent>1</idCdcParent>
            <cdcName>testMOD</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>5</idCdc>
            <idCdcParent>1</idCdcParent>
            <cdcName>testMOD</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>6</idCdc>
            <idCdcParent>1</idCdcParent>
            <cdcName>testMOD</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList>
                <cdc>
                    <idCdc>7</idCdc>
                    <idCdcParent>6</idCdcParent>
                    <cdcName>testMODChild</cdcName>
                    <order>4</order>
                    <isUsed>false</isUsed>
                    <cdcList/>
                </cdc>
            </cdcList>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>2</idCdc>
      <idCdcParent>0</idCdcParent>
      <cdcName>Progetti</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>8</idCdc>
            <idCdcParent>2</idCdcParent>
            <cdcName>testGP</cdcName>
            <order>1</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>9</idCdc>
            <idCdcParent>2</idCdcParent>
            <cdcName>testGPS</cdcName>
            <order>2</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
         <cdc>
            <idCdc>10</idCdc>
            <idCdcParent>2</idCdcParent>
            <cdcName>EOS</cdcName>
            <order>3</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>3</idCdc>
      <idCdcParent>0</idCdcParent>
      <cdcName>Milano</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>11</idCdc>
            <idCdcParent>3</idCdcParent>
            <cdcName>l</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
</cdcList>

标签: xmlxslthierarchical-data

解决方案


你的错误在这里:

<xsl:variable name="root" select="/nsc:cdcDbSet/nsc:cdcEntity/nsc:idCdcParent"/>

这不会选择单个节点,更不用说根节点,甚至是根节点的ID。

它选择所有 <nsc:idCdcParent>元素。连同这个

<xsl:apply-templates select="nsc:cdcEntity[nsc:idCdcParent=$root]"/>

where [nsc:idCdcParent=$root]always 为真,因为所有<nsc:idCdcParent>都在 中$root,并且递归步骤

<xsl:apply-templates select="key('nodeChildren',nsc:idCdc)"/>

您多次浏览输入文档,导致重复输出。


假设根节点的 ID 为 1,这将生成一个正确嵌套的树。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:nsc="http://eos.mcr.com/cdc/anagrafica/ds"
    xmlns="http://ws.apache.org/ns/synapse"
    exclude-result-prefixes="nsc"
>
    <xsl:output indent="yes" />
    <xsl:key name="nodesByParent" match="nsc:cdcEntity" use="nsc:idCdcParent"/>

    <xsl:template match="nsc:cdcDbSet">
        <cdcList>
            <xsl:apply-templates select="key('nodesByParent', 1)"/>
        </cdcList>
    </xsl:template>

    <xsl:template match="nsc:cdcEntity">
        <cdc>
            <xsl:apply-templates mode="copy-local" select="
                nsc:idCdc|nsc:idCdcParent|nsc:cdcName|nsc:order|nsc:isUsed
            " />
            <cdcList>
                <xsl:apply-templates select="key('nodesByParent', nsc:idCdc)"/>
            </cdcList>
        </cdc>
    </xsl:template>

    <xsl:template match="*" mode="copy-local">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

笔记

  • 顶级默认xmlns声明,因此您无需在样式表正文中重复自己
  • exclude-result-prefixes属性_
  • 通过使用模板输出具有相同本地名称的任何元素来减少重复

结果:

<cdcList xmlns="http://ws.apache.org/ns/synapse">
   <cdc>
      <idCdc>15</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Caserta</cdcName>
      <order>1</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>14</idCdc>
            <idCdcParent>15</idCdcParent>
            <cdcName>testMOD</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>16</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>testGP</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>11</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>figlio</cdcName>
      <order>2</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>10</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>3</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>3</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Milano</cdcName>
      <order>4</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>7</idCdc>
            <idCdcParent>3</idCdcParent>
            <cdcName>l</cdcName>
            <order>4</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
   <cdc>
      <idCdc>8</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>pippo</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
      <cdcList/>
   </cdc>
   <cdc>
      <idCdc>4</idCdc>
      <idCdcParent>1</idCdcParent>
      <cdcName>Napoli</cdcName>
      <order>5</order>
      <isUsed>false</isUsed>
      <cdcList>
         <cdc>
            <idCdc>9</idCdc>
            <idCdcParent>4</idCdcParent>
            <cdcName>cccc</cdcName>
            <order>6</order>
            <isUsed>false</isUsed>
            <cdcList/>
         </cdc>
      </cdcList>
   </cdc>
</cdcList>

推荐阅读