嘿朋友们 我有另一个xsl / xpath问题。确实是一个初学者问题,但我认为仍然太“必要”。
<!-- XML -->
<Module>
<WideTeaserElement>
<Headline>Bla bla 1</Headline>
</WideTeaserElement>
<WideTeaserElement>
<Headline>Bla bla 2</Headline>
</WideTeaserElement>
</Module>
<!-- XSL -->
<!-- You are already in the Node Module -->
<xsl:template match="WideTeaserElement">
<ul class="TabbedPanelsTabGroup">
<xsl:for-each select=".">
<li class="TabbedPanelsTab"><a href="#"><xsl:value-of select="pub:Headline"/></a></li>
</xsl:for-each>
</ul>
</xsl>
我想得到的是输出:
<ul class="TabbedPanelsTabGroup">
<li class="TabbedPanelsTab"><a href="#">Bla bla 1</a></li>
<li class="TabbedPanelsTab"><a href="#">Bla bla 2</a></li>
</ul>
使用我的XSL,我得到一个带有两个<ul>
元素的输出。所以我的问题包括两件事:
1)如何改变我的问题?
2)如何在XSL中处理像for-each这样的循环,让它更“受控制”?
答案 0 :(得分:2)
你几乎从不需要在XSL中使用for-each
,如果你发现自己使用它,你可能会错过XSL的重要功能。
通过为HeadLine
元素(包含<li>...</li>
元素)提供模板,然后在<xsl:apply-templates/>
元素中使用<ul>
,可以更恰当地表达您的案例在WideTeaserElement
模板中。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match='Module'>
<ul class='TabbedPanelsTabGroup'>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match='Headline'>
<li class='TabbedPanelsTab'><a href='#'><xsl:apply-templates/></a></li>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:2)
这种转变(完全符合XSLT的精神):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="Module">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="Headline">
<li class="TabbedPanelsTab"><a href="#"><xsl:value-of select="."/></a></li>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<Module>
<WideTeaserElement>
<Headline>Bla bla 1</Headline>
</WideTeaserElement>
<WideTeaserElement>
<Headline>Bla bla 2</Headline>
</WideTeaserElement>
</Module>
产生所需的结果:
<ul>
<li class="TabbedPanelsTab">
<a href="#">Bla bla 1</a>
</li>
<li class="TabbedPanelsTab">
<a href="#">Bla bla 2</a>
</li>
</ul>
答案 2 :(得分:1)
您获得两个ul
元素的原因是因为生成ul
元素的模板与名为WideTeaserElement
的元素匹配,其中有两个元素。
我想我可以看到思考与此有何关系 - 你是否假设这个模板将在一个操作中处理所有WideTeaserElement
,然后你可以用'为每个'进行迭代?相反,每次出现WideTeaserElement
节点时都会单独调用模板,然后通过单次出现来“迭代”。
我同意诺曼的观点,for-each
很少是最佳选择,但我可以想到你可能会使用它的两个原因。
对于(非常简化的)例子,我赞成
<xsl:template match="mylist">
<xsl:element name="ul">
<xsl:for-each select="listitem">
<xsl:element name="li">
<xsl:value-of select="." />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
而不是
<xsl:template match="mylist">
<xsl:element name="ul">
<xsl:apply-templates select="listitem" />
</xsl:element>
</xsl:template>
<xsl:template match="listitem">
<xsl:element name="li">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
如果mylist
模板实际上有更多代码,后一种解决方案意味着必须向下滚动我的代码才能看到listitem
的处理方式。这是主观的,有些人可能总是喜欢后一种解决方案。就个人而言,我通常发现大多数模板足够大,破坏它们对于可读性更好,但在较小的模板中并非总是这样。
listitem
标记,而不仅仅是'mylist'标记内的标记。当然可以通过将匹配更改为listitem[parent::mylist]
来限制它,但for-each
通常比基于祖先为同一元素名称制作多个模板更简洁。一般来说,您通常可以替换
<xsl:template match="foo">
<xsl:for-each select="bar">
..
</xsl:for-each>
</xsl:template>
与
<xsl:template match="foo">
<xsl:apply-templates select="bar" />
</xsl:template>
<xsl:template match="bar">
..
</xsl:template>
在bar
元素始终具有foo
元素的任何文档中,作为其父元素。