如何使用xslt检查现有节点及其包含在xml文件中,并用节点号对节点进行差异化

时间:2012-09-12 12:54:33

标签: xslt xslt-1.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-number来区分具有相同名称和相同名称的两个节点。当节点使用不同的包含相同的名称时(也必须将节点包含中的空格视为差异),然后让节点保持原样。 如何使用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 ”,包含是不同的,那么我想保留它们unchange,如果没有,我想添加一个id号来区别。

1 个答案:

答案 0 :(得分: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>

... INTO ...

<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(),'|',.)静音几次,并且在我们无法直接访问此上下文节点的地方,我们只计算concat()和替换像这样进入Set 2。现在可以快速计算第2组。

    设置2

    key('kCommon',$this-key)
    
  3. 然后我们使用Kaysian method进行集合交集。

     $set1[count(.|$set2)=count($set2)]
    
  4. 这个交集是在它之前的所有相似元素的集合。我们只计算它们并添加一个,这给了我们id属性的序数。