我的理解是,<xsl:template />
和<xsl:for-each>
的使用几乎可以达到相同的目的,<xsl:for-each >
是一种“匿名内联模板”。< / p>
问题但是,考虑到以下情况,我认为使用<xsl:for-each>
更合适。
请验证我的理解,或者是否有办法通过<xsl:template>
来实现输出?
输入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 >
] - 这会提供预期的输出
<?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 >
]
<?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>
这不会给出预期的输出,而是获得的输出是
<?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
,因为上下文是每个<book>
元素。但为什么它不适用于模板?
我也试过<xsl:number>
,但无法按预期工作
<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 [不递增]
请帮忙。
注意:我使用XSLT转换为输出XML,与输入XML相比,它具有完全不同的标记集,因此我不使用模板进行复制。
答案 0 :(得分:1)
我认为您对这些差异的理解有点不对,但这不是问题所在,因为您的<xsl:apply-templates />
基本上与<xsl:for-each>
相同。
但是:您在两个代码段中使用的选择器有很大差异。您的第一个示例使用了<xsl:for-each select="books/*">
,它创建了一个基数为2的节点集,编号,毫不奇怪,1和2.您的第二个代码段使用<xsl:apply-templates />
,这是<xsl:apply-templates select="node()">
的简写,以及创建基数为五(!)的节点集,其中节点1,3和5是文本节点(恰好只包含空格),节点2和4是您实际想要定位的节点。
解决方案?将您的选择器添加到apply-templates
元素,如<xsl:apply-templates select="books/*" />
。
编辑那么,为什么在第二种情况下设置的节点很大?因为它拾取books
的所有子节点,并且XML的工作方式不仅包括元素 - 它还包括文本节点(您确实希望<title>
和<author>
拥有一个文本节点子) - 包括来自你的缩进的文本节点,只包含行尾和空格和/或制表符之类的东西,统称为空格。在这些输入变体上尝试原始的第二个代码:
<?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>
另请注意,元素和文本不是唯一的节点类型:
<?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只是默认忽略apply-templates中不匹配的节点。