我需要只使用XSLT缩短XML文档中的一些ID值及其引用…
示例XML文档:
<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标记相同的标记替换它们。
Edit -替换值需要是一个递增的数字。我认为使其递增的最好方法是在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>
如何:
<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值的目的是什么;只要它们是独一无二的,谁在乎它们有多长呢?
我更关心的是如何(如果可能的话):匹配ID标记,将其文本节点更改为新值2。然后匹配任何IDRef并将其文本替换为与添加到的内容相同的值第1步中的ID标签
嗯,这实际上取决于第一步是如何执行的。因为IDRef总是可以得到源文档中的原始ID元素——但不能得到结果树中转换后的对应元素。