0

是否有可能检查 xml 文件中是否存在重复节点,然后检查该节点的包含,如果可能,使用 xslt 通过 ID 号区分两个节点?例如,我有这个 xml 文件

<Racine>
  <el1>
   <fils1>context1</fils1>
   <fils2>test1</fils2>
   <fils1>context1</fils1>
  </el1>
  <el2>
   <fils1>context2</fils1>
   <fils2>test2</fils2>
   <fils1>context2</fils1>
  </el2>
  <el3>...........<el3>
</Racine>

例如,在这种情况下,节点“ fils1 ”在节点“ el1 ”中出现了两次,并且它们中的每一个的包含都是相同的。在这种情况下,我需要转换我的 xml 文件,以便该节点变为

<fils1 id=1>context1</fils1>.

我自动添加一个 ID 号来区分具有相同名称和相同包含的两个节点。并且当节点具有不同的包含相同的名称时(也必须将节点的包含中的空格视为差异),然后让节点保持原样。如何使用 XSLT 使这成为可能?这里有人可以帮我改变吗?非常感谢你的帮助。
弗兰奇

谢谢你的发言。这是预期的输出:

<Racine>
  <el1>
   <fils1 id=1>context1</fils1>
   <fils2>test1</fils2>
   <fils1 id=2>context1</fils1>
  </el1>
  <el2>
   <fils1 id=1>context2</fils1>
   <fils2>test2</fils2>
   <fils1 id=2>context2</fils1>
  </el2>
  <el3>...........
   <fils1 id=3>context1</fils1>
  <el3>
</Racine>

将“ el1 ”和“ el2 ”中的节点“ fils2 ”连接起来,包含不同,然后我想让它们保持不变,如果不改变,我想添加一个 id 号来产生差异。

4

1 回答 1

0

这个 XSLT 1.0 样式表...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />

<xsl:key name="kCommon" match="*[starts-with(name(),'fils')]"
                        use="concat(name(),'|',.)" />

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

<xsl:template match="*[starts-with(name(),'fils')]
                      [count(key('kCommon',concat(name(),'|',.))) >= 2]">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:variable name="this-key" select="concat(name(),'|',.)" />
    <xsl:attribute name="id"><xsl:value-of select="
      count(preceding::*
             [starts-with(name(),'fils')]
             [count(.|key('kCommon',$this-key)) =
              count(  key('kCommon',$this-key))    ]
            ) + 1" /></xsl:attribute>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>
</xsl:template>  

</xsl:stylesheet>

...将转换此输入...

<Racine>
  <el1>
   <fils1>context1</fils1>
   <fils2>test1</fils2>
   <fils1>context1</fils1>
  </el1>
  <el2>
   <fils1>context2</fils1>
   <fils2>test2</fils2>
   <fils1>context2</fils1>
  </el2>
  <el3>
   <fils1>context1</fils1>
  </el3>
</Racine>

...进入...

<Racine>
  <el1>
    <fils1 id="1">context1</fils1>
    <fils2>test1</fils2>
    <fils1 id="2">context1</fils1>
  </el1>
  <el2>
    <fils1 id="1">context2</fils1>
    <fils2>test2</fils2>
    <fils1 id="2">context2</fils1>
  </el2>
  <el3>
    <fils1 id="3">context1</fils1>
  </el3>
</Racine>

解释

我们为具有通用名称和通用文本内容的 fils 元素构建一个键 ('kCommon')。我们寻找在他们的键组中至少有两个成员的元素——换句话说,filX 类型的元素具有与至少一个其他 filX 元素相同的名称和文本。这是我们的最后一个模板。

对于每个这样的公共元素,我们构建了两个集合:

  1. 公共组中所有前面的 fil 元素的集合。这一套是由...

    设置 1

    preceding::*[starts-with(name(),'fils')]
    
  2. 而这个节点的通用名+内容组,也就是……

    设置 2

    key('kCommon',concat(name(),'|',.))
    

    但是因为我们将引用 concat(name(),'|',.) quiet 几次,并且在我们无法直接访问此上下文节点的地方,我们只需计算 concat() 并替换为 Set 2像这样。Set 2 现在可以快速计算。

    设置 2

    key('kCommon',$this-key)
    
  3. 然后我们使用Kaysian 方法取一个集合交集。

     $set1[count(.|$set2)=count($set2)]
    
  4. 这个交集是所有志同道合的元素的集合。我们只是将它们数起来并加一个,这为我们提供了 id 属性的序数。

于 2012-09-12T14:41:25.777 回答