XSLT 允许您递归地遍历节点树。在遍历您的树时,您可以通过创建比其他模板规则更具体的模板规则来让 XSLT 处理您的节点。
您要解决的问题是在转换您的 XML 树时有一些细微的差别。一个好的开始是进行身份转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
此身份转换将简单地生成与输入 XML 相同的 XML 输出。它按原样匹配并复制每个 XML 节点。然后你一步一步地塑造你的输出,直到你得到你想要的。请参阅<xsl:copy/>
.
您要进行的此复制的例外情况是遇到没有任何子节点的元素时。为了匹配任何元素,我们使用*
. 为了不匹配任何元素,我们使用not(*)
. 为了匹配没有元素的任何元素,我们因此使用*[not(*)]
. 事实上,这些规则是由XSLT 使用的XPath查询语言定义的。让我们针对您的 XML 尝试以下 XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<found-an-element-with-no-children/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我们得到:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<found-an-element-with-no-children/>
<found-an-element-with-no-children/>
</HDR>
<DSC>
<found-an-element-with-no-children/>
</DSC>
</DEV>
好处是任何一个节点一次只能匹配一个模板规则。我们看起来更接近我们现在想要的位置。
这就是<xsl:copy/>
进来的地方。我们现在将使用它,因为我们想要复制原始元素的名称。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<found-an-element-with-no-children/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
现在我们得到:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID><found-an-element-with-no-children/></ApID>
<STAT><found-an-element-with-no-children/></STAT>
</HDR>
<DSC>
<Cap><found-an-element-with-no-children/></Cap>
</DSC>
</DEV
现在为我们新创建的节点添加一个属性,并在其中包含我们刚才匹配的节点的文本内容:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<xsl:attribute name="V">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
看起来我们在这里:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID V="value1"/>
<STAT V="value2"/>
</HDR>
<DSC>
<Cap V="value3"/>
</DSC>
</DEV>
现在有几个指针:
- 您的 , 都没有
ApID
,STAT
并且Cap
将能够复制其旧属性。您将希望<xsl:apply-templates select="@*"/>
包含这些属性。
- 当你包含这些属性时,如果原始输入包含一个
V
属性会发生什么?
- 您可能还需要考虑当您匹配的标签没有文本时会发生什么 - 以及原因。