XSLT 1.0 在 <xsl:for-each> 中使用 position()和 <xsl:template> [英] XSLT 1.0 Using position() in <xsl:for-each> and <xsl:template>
问题描述
我的理解是,
和
的用法几乎达到了相同的目的,<xsl:for-each >
是一种匿名内联模板".
My understanding is that the usage of <xsl:template />
and <xsl:for-each>
almost serve the same purpose and <xsl:for-each >
is a sort of "anonymous inline template".
问题:但是,考虑到以下场景,我认为使用
更合适.请验证我的理解,或者有没有办法也可以通过
实现输出?
Question: However, considering the below scenario, i think using <xsl:for-each>
is more appropriate.
Please validate my understanding, or is there a way the output can be achieved through <xsl:template>
as well?
输入 XML:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
预期输出:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="book1">
<title>charithram</title>
<author>sarika</author>
</book>
<book id="book2">
<title>doublebell</title>
<author>psudarsanan</author>
</book>
</books>
XSLT1 [使用 <xsl:for-each >
] - 这给出了预期的输出
XSLT1 [using <xsl:for-each >
] - This gives the expected output
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="/">
<newbooks>
<xsl:for-each select="books/*">
<newbook id="book{position()}">
<title><xsl:value-of select="title" /></title>
<author> <xsl:value-of select="author" /></author>
</newbook>
</xsl:for-each>
</newbooks>
</xsl:template>
</xsl:stylesheet>
XSLT2 [使用 <xsl:template >
]
XSLT2 [using <xsl:template >
]
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="/">
<newbooks>
<xsl:apply-templates/>
</newbooks>
</xsl:template>
<xsl:template match="books/*" >
<newbook id="book{position()}">
<title><xsl:value-of select="title" /></title>
<author> <xsl:value-of select="author" /></author>
</newbook>
</xsl:template>
</xsl:stylesheet>
这并没有给出预期的输出,而是获得的输出是,
This does not give the expected output, Instead, the output obtained is,
<?xml version="1.0" encoding="UTF-8"?>
<newbooks>
<newbook id="book2">
<title>charithram</title>
<author>sarika</author>
</newbook>
<newbook id="book4">
<title>doublebell</title>
<author>psudarsanan</author>
</newbook>
</newbooks>
我能想到获得 2 和 4 的唯一原因可能是 id
节点在上下文中的位置.position()
函数返回上下文节点在选定节点集中的位置".根据这个定义,它适用于 for-each
的情况,因为上下文是每个
元素.但是为什么它不适用于模板的情况?
The only reason i can think of getting 2 and 4, could be the position of id
node inside the context.
"The position()
function returns the position of the context node in a selected set of nodes". As per this definition, it works in the case of for-each
as the context is each <book>
element. But why it is not applicable in the case of template?
我也尝试过 <xsl:number>
,但无法使其按预期工作
I also tried with <xsl:number>
, but cannot make it to work as expected
<xsl:template match="/">
<newbooks>
<xsl:apply-templates/>
</newbooks>
</xsl:template>
<xsl:template match="books/*" >
<newbook >
<xsl:attribute name="id">
<xsl:text>book</xsl:text><xsl:number/>
</xsl:attribute>
<title><xsl:value-of select="title" /></title>
<author> <xsl:value-of select="author" /></author>
</newbook>
</xsl:template>
我得到 book1, book1 的输出 [不递增]
I am getting the output of book1, book1 [not incrementing]
请帮忙.
注意:我使用 XSLT 转换为输出 XML,与输入 XML 相比,它具有完全不同的标签集,因此我不使用模板进行复制.
Note: I use XSLT to transform into output XML which has complete different set of tags compared to input XML, so I don't use a template to copy.
推荐答案
我认为您对差异的理解有点错误,但这不是这里的问题,因为您的 <xsl:apply-templates/>
本质上与
的作用相同.
I think your understanding of the differences is a bit faulty, but that is not the issue here, since your <xsl:apply-templates />
essentially does the same as an <xsl:for-each>
.
但是:您在两个代码片段中使用的选择器存在重大差异.您的第一个示例使用 <xsl:for-each select="books/*">
,它创建了一个基数为 2 的节点集,编号,毫不奇怪,1 和 2.您的第二个代码片段使用
,它是
的简写,它创建基数为 5(!) 的节点集,节点 1、3 和 5 是文本节点(碰巧只包含空格),节点 2 和 4 是您实际想要定位的节点.
But: You have a major difference in the selectors you use in the two code snippets. Your first example uses <xsl:for-each select="books/*">
, which creates a node set of cardinality two, numbered, unsurprisingly, 1 and 2. Your second code snippet uses <xsl:apply-templates />
, which is a shorthand for <xsl:apply-templates select="node()">
, and that creates a node set of cardinality five(!), with nodes 1, 3, and 5 being text nodes (that happen to only contain whitespace), and nodes 2 and 4 being the ones you actually want to target.
解决方案?将您的选择器添加到 apply-templates
元素,如 <xsl:apply-templates select="books/*"/>
.
Solution? Add your selector to the apply-templates
element, as in <xsl:apply-templates select="books/*" />
.
EDIT 那么,为什么第二种情况下的节点集那么大?因为它选取了 books
的所有子节点,而且 XML 的工作方式不仅包括元素——它还包括文本节点(你确实想要你的
> 和
有一个文本节点子节点)——包括源自缩进的文本节点, 只包含行尾和空格等内容和/或制表符,统称为空格.在这些输入变体上尝试原始的第二个代码:
EDIT So, why is the node set in the second case that big? Because it picks up all child nodes of books
, and the way XML works is that that includes not only elements – it also includes text nodes (you do want your <title>
and <author>
to have a text node child) – including the text nodes that stem from your indenting, which only contain things like end-of-line and spaces and/or tabs, collectively known as whitespace. Try the original second code on these input variations:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
.
<?xml version="1.0" encoding="UTF-8"?>
<books><book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
.
<?xml version="1.0" encoding="UTF-8"?>
<books><book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1><book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
另请注意,元素和文本并不是唯一的节点类型:
Also note that elements and text are not the only types of nodes:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<!-- first book -->
<book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<!-- second book -->
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
如果您有与这些匹配的模板(例如 <xsl:template match='text()'>
或更具体的东西),您会在那里找到相应的输出.XSLT 只是默认忽略应用模板中不匹配的节点.
If you had templates matching these (such as an <xsl:template match='text()'>
or maybe something more specific), you’d find the corresponding output there. XSLT just defaults to ignoring unmatched nodes in apply-templates.
这篇关于XSLT 1.0 在 <xsl:for-each> 中使用 position()和 <xsl:template>的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!