我有以下XML。它包含书籍和参考。一些参考文献追溯到第1册,例如第4册参考第3册,第3册涉及第1册。
<?xml version="1.0" encoding="UTF-8"?>
<sandbox>
<book xml:id="h1">
<name>Book 1</name>
</book>
<book xml:id="h2">
<name>Book 2</name>
</book>
<book xml:id="h3">
<name>Book 3</name>
<ref target="#h1"/>
</book>
<book xml:id="h4">
<name>Book 4</name>
<ref target="#h3"/>
</book>
</sandbox>
我编写了以下XSLT,它通过追溯对原始源的引用并添加相应的文本语句来丰富代码:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:sandbox="sandbox.org"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:function name="sandbox:trace">
<xsl:param name="target"/>
<xsl:choose>
<xsl:when test="document($target)/ref">
<xsl:value-of select="sandbox:trace(document($target)/ref/@target)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="document($target)/name"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:template match="ref">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:text>This book refers to </xsl:text>
<xsl:value-of select="sandbox:trace(@target)"/>
<xsl:text>!</xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
它产生所需的输出:
<?xml version="1.0" encoding="UTF-8"?>
<sandbox>
<book xml:id="h1">
<name>Book 1</name>
</book>
<book xml:id="h2">
<name>Book 2</name>
</book>
<book xml:id="h3">
<name>Book 3</name>
<ref target="#h1">This book refers to Book 1!</ref>
</book>
<book xml:id="h4">
<name>Book 4</name>
<ref target="#h3">This book refers to Book 1!</ref>
</book>
</sandbox>
我的问题:这是一种“好”的方式还是更适合这项任务的解决方案?
给定引用和id我通常很想使用xsl:key
和key
函数,在你的情况下因为输入使用xml:id
属性甚至不是必要的,因为你可以简单地使用id
函数然后找到引用的元素。所以这看起来更简单:
<xsl:stylesheet version="2.0" xmlns:sandbox="sandbox.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xs sandbox">
<xsl:output indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:function name="sandbox:check-ref" as="xs:string">
<xsl:param name="target" as="element(book)"/>
<xsl:sequence select="if ($target/ref)
then sandbox:check-ref($target/ref/id(substring(@target, 2)))
else $target/name"/>
</xsl:function>
<xsl:template match="ref">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:text>This book refers to </xsl:text>
<xsl:value-of select="sandbox:check-ref(id(substring(@target, 2)))"/>
<xsl:text>!</xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我还添加了类型注释作为XSLT 2处理器的实现者,如Michael Kay通常指出它是一种提高类型安全性和代码性能的方法。