我需要遍历多节点结构,但此结构仅由前导节点标识,并且该前导节点之后的节点可以变化。
在此示例中,我需要遍历每个<title>-some_nodes
,<title>-some_other_nodes
块
XML文件:
<books>
<title>book_one</title>
<price>price_for_book_one</price>
<notes>notes_for_book_one</notes>
<title>book_two</title>
<price>price_for_book_two</price>
</books>
期望的输出:
<div class="book">
<h1 id="title">book_one</h1>
<h2 id="values">
<p>price_for_book_one</p>
<p>notes_for_book_one</p>
</h2>
</div>
<div class="book">
<h1 id="title">book_two</h1>
<h2 id="values">
<p>price_for_book_two</p>
</h2>
</div>
我的尝试:
<xsl:template match="/">
<xsl:for-each select="books/title">
<h1 id="title"><xsl:text>Title:</xsl:text>
<xsl:value-of select="." />
</h1>
<h2 id="values">
<!-- have other templates for matching all possible following-sibling nodes -->
<xsl:apply-templates select="following-sibling::*>
</h2>
</xsl:for-each>
</xsl:template>
但是这只选择标题节点而不解析任何其他节点,因为“books / title”只选择标题节点。
注意:<price>
和<notes>
是两个示例节点,<title>
节点之间可能有任何内容,我有其他模板可以处理它们,但是如何选择它们是我的问题。
任何想法都会非常感激。
答案 0 :(得分:1)
在您的循环中,上下文节点为title
,因此选择.
。
您可能只想要标题后面的第一个价格和注释元素。我还使用xsl:text
来减少每个段落中的空格。
<xsl:template match="/">
<xsl:for-each select="books/title">
<p>
<xsl:text>Title: </xsl:text>
<xsl:value-of select="." />
</p>
<p>
<xsl:text>Price: </xsl:text>
<xsl:value-of select="following-sibling::price[1]"/>
</p>
<p>
<xsl:text>Notes: </xsl:text>
<xsl:value-of select="following-sibling::notes[1]"/>
</p>
</xsl:for-each>
</xsl:template>
如果每个title
之间的其他节点没有修复,您可以使用模板处理每个节点。这里重要的是XPath表达式,用于选择属于当前标题的非标题元素。
<xsl:template match="/">
<xsl:for-each select="books/title">
<p>
<xsl:text>Title:</xsl:text>
<xsl:value-of select="." />
</p>
<xsl:apply-templates select="following-sibling::*[
local-name() != 'title' and
preceding-sibling::title[1] = current()]"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="price">
<p>
<xsl:text>Price: </xsl:text>
<xsl:value-of select="."/>
</p>
</xsl:template>
答案 1 :(得分:1)
首先,您似乎不需要分组。这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="books/*">
<p>
<xsl:value-of
select="concat(translate(
substring(local-name(),1,1),
'qwertyuiopasdfghjklzxcvbnm',
'QWERTYUIOPASDFGHJKLZXCVBNM'
),
substring(local-name(),2),
': ',
.
)" />
</p>
</xsl:template>
</xsl:stylesheet>
输出:
<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>
只有当你要对小组做一些事情时才需要分组,例如包裹:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByPrecedingTitle"
match="books/*"
use="generate-id((.|preceding-sibling::*)[self::title][last()])"/>
<xsl:template match="books/*">
<p>
<xsl:value-of
select="concat(translate(
substring(local-name(),1,1),
'qwertyuiopasdfghjklzxcvbnm',
'QWERTYUIOPASDFGHJKLZXCVBNM'
),
substring(local-name(),2),
': ',
.
)" />
</p>
</xsl:template>
<xsl:template match="books">
<xsl:for-each select="title">
<div class="book">
<xsl:apply-templates
select="key('kElementByPrecedingTitle',generate-id())"/>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<div class="book">
<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
</div>
<div class="book">
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>
</div>