如何使用XSLT1.0替换XML文件中的ID元素及其所有引用元素

时间:2014-06-18 06:20:50

标签: xml xslt xslt-1.0

我只需要使用XSLT ......

缩短XML文档中的一些ID值及其引用

示例XML doc:

<root>
 <firstChild>
  <ID>99999</ID>
 </firstChild>
 <secondChild>
  <IDRef>99999</IDRef>
 </secondChild>
 <thirdChild>
  <person>
   <IDRef>99999</IDRef>
  </person>
 </thirdChild>
</root>

应用XSLT后的所需结果:

<root>
 <firstChild>
  <ID>1</ID>
 </firstChild>
 <secondChild>
  <IDRef>1</IDRef>
 </secondChild>
 <thirdChild>
  <person>
   <IDRef>1</IDRef>
  </person>
 </thirdChild>
</root>

基本上我需要XSLT来查找每个ID标签,用一个值替换它,然后在文档的其他地方找到任何IDRef标签,并用ID标签替换它们。

编辑 - 替换值必须是递增数字。我认为使其增量的最佳方法是使用xslt中的position()函数。例如:

<xsl:variable name="ReplacementID" Select="position()"/>

我不太关心如何在这个阶段增加数字,我更关心如何(如果有可能): 1.匹配ID标签,将其文本节点更改为新值, 2.然后匹配任何IDRef节点,并将其文本替换为与步骤1中添加到ID标记的值相同的值 值本身可以是从全局变量到传递给样式表的参数的任何内容。

下面是我正在尝试做的非常粗略的XSLT(它不起作用)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
    <xsl:apply-templates select="@* | node()"/>
</xsl:template>

<xsl:template match="root/firstChild/ID">
    <xsl:variable name="currentID" select="."/>
    <xsl:variable name="replacementID">1</xsl:variable>
    <ID>
        <xsl:value-of select="$replacementID"/>
    </ID>
    <xsl:apply-templates select="IDRef[text() = $currentID]" mode="Replace">
        <xsl:with-param name="Replacement" select="$replacementID"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="IDRef" mode="Replace">
    <xsl:param name="Replacement"/>
    <IDRef>
        <xsl:value-of select="$Replacement"/>
    </IDRef>
</xsl:template>

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

1 个答案:

答案 0 :(得分:2)

怎么样:

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

<xsl:key name="id" match="ID" use="." />

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

<xsl:template match="ID">
    <xsl:copy>
        <xsl:value-of select="count(preceding::ID) + 1" />
    </xsl:copy>
</xsl:template>

<xsl:template match="IDRef">
    <xsl:copy>
        <xsl:value-of select="count(key('id', .)/preceding::ID) + 1" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

应用于以下测试输入:

<root>
    <master>
        <ID>12345</ID>
    </master>
    <slave>
        <IDRef>12345</IDRef>
    </slave>
    <element>
        <slave>
            <IDRef>987</IDRef>
        </slave>
    </element>
    <master>
        <ID>987</ID>
    </master>
    <slave>
        <IDRef>987</IDRef>
    </slave>
    <element>
        <slave>
            <IDRef>12345</IDRef>
        </slave>
    </element>
</root>

结果是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <master>
      <ID>1</ID>
   </master>
   <slave>
      <IDRef>1</IDRef>
   </slave>
   <element>
      <slave>
         <IDRef>2</IDRef>
      </slave>
   </element>
   <master>
      <ID>2</ID>
   </master>
   <slave>
      <IDRef>2</IDRef>
   </slave>
   <element>
      <slave>
         <IDRef>1</IDRef>
      </slave>
   </element>
</root>

-
顺便说一句,我不太清楚ID值缩短的目的是什么;只要它们是独一无二的,谁在乎它们有多长?


  

我更关心如何(如果可能):1。匹配ID   tag,将其文本节点更改为新值,然后匹配任何IDRef   节点并用与添加的值相同的值替换它们的文本   步骤1中的ID标记

嗯,这实际上取决于步骤1的执行方式。因为IDRef总是可以到达源文档中的原始ID元素 - 但不能到达结果树中的已转换对应元素。