我有多个xml实例,类似于以下内容:
<refbody>
<ul>
<li><uicontrol>FOO</uicontrol>BAR</li>
</ul>
<p>Values: 000 - 999</p>
<ul>
<li><uicontrol>FOO</uicontrol>BAR</li>
<li><uicontrol>FOO</uicontrol>BAR</li>
<li><uicontrol>FOO</uicontrol>BAR</li>
<li><uicontrol>FOO</uicontrol>BAR</li>
</ul>
<p>Values:</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</refbody>
我希望将所有<ul>
元素合并为一个<dl>
。
每个<li>
都应该创建一个子<dlentry>
。
每个<uicontrol>
应该成为<dt>
的{{1}}个孩子。
<dlentry>
中的其余文字应放在<li>
元素中,该元素也是<dd>
的子元素。
我的样式表(下面提供)已经完成了很多。我遇到麻烦的地方是最后一项要求:
任何<dlentry>
都需要放在与其<p>
关联的<dlentry>
内。
所以期望的结果如下所示:
preceding-sibling::li[1]
我认为我需要使用密钥来执行此操作,但我无法让它正常工作。如果有人能告诉我我做错了什么,我真的很感激。
这是我的样式表:
<refbody>
<dl>
<dlentry>
<dt>FOO</dt>
<dd>BAR
<p>Values: 000 - 999</p>
</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR
<p>Values:</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</dd>
</dlentry>
</dl>
</refbody>
答案 0 :(得分:1)
以下样式表无需使用键即可生成所需的输出。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="refbody">
<xsl:copy>
<dl>
<xsl:apply-templates select="ul" />
</dl>
</xsl:copy>
</xsl:template>
<xsl:template match="ul">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="li">
<dlentry><xsl:apply-templates select="@*|node()"/></dlentry>
</xsl:template>
<xsl:template match="uicontrol">
<dt><xsl:apply-templates select="@*|node()"/></dt>
</xsl:template>
<xsl:template match="li/text()">
<dd>
<xsl:copy/>
<xsl:apply-templates
select="parent::li
[not(following-sibling::li)]
/parent::ul
/following-sibling::p
[
count(preceding-sibling::ul)
= count(current()/../../preceding-sibling::ul)
+1
]"/>
</dd>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
<强>予。这种转变(我使用密钥的解决方案):
<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:key name="kFollowing"
match="node()[self::p or self::text() and preceding-sibling::ul]"
use="generate-id(preceding::li[1])"/>
<xsl:template match="/*[ul]">
<refbody>
<dl>
<xsl:apply-templates/>
</dl>
</refbody>
</xsl:template>
<xsl:template match="li">
<dlentry>
<xsl:apply-templates/>
</dlentry>
</xsl:template>
<xsl:template match="li/text()">
<dd>
<xsl:value-of select="normalize-space()"/>
</dd>
</xsl:template>
<xsl:template match="li[last()]/text()">
<dd>
<xsl:value-of select="."/>
<xsl:copy-of select="key('kFollowing', generate-id(..))"/>
</dd>
</xsl:template>
<xsl:template match="uicontrol">
<dt>
<xsl:apply-templates/>
</dt>
</xsl:template>
<xsl:template match="p/text()"/>
</xsl:stylesheet>
应用于提供的XML文档:
<refbody>
<ul>
<li>
<uicontrol>FOO</uicontrol>BAR
</li>
</ul>
<p>Values: 000 - 999</p>
<ul>
<li>
<uicontrol>FOO</uicontrol>BAR
</li>
<li>
<uicontrol>FOO</uicontrol>BAR
</li>
<li>
<uicontrol>FOO</uicontrol>BAR
</li>
<li>
<uicontrol>FOO</uicontrol>BAR
</li>
</ul>
<p>Values:</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</refbody>
生成想要的正确结果:
<refbody>
<dl>
<dlentry>
<dt>FOO</dt>
<dd>BAR
<p>Values: 000 - 999</p>
</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR</dd>
</dlentry>
<dlentry>
<dt>FOO</dt>
<dd>BAR
<p>Values:</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</dd>
</dlentry>
</dl>
</refbody>
<强> II。纠正所有发现错误后的解决方案:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kValues" match="p"
use="generate-id(preceding::li[1])"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ul[ancestor::refbody][1]">
<dl>
<xsl:for-each select="child::li|following::li">
<xsl:variable name="vValues" select="key('kValues',generate-id())"/>
<dlentry>
<dt>
<xsl:value-of select="child::uicontrol"/>
</dt>
<dd>
<xsl:value-of select="text()[normalize-space()]"/>
<xsl:copy-of select="$vValues" />
</dd>
</dlentry>
</xsl:for-each>
</dl>
</xsl:template>
<xsl:template match="p|ul|text()"/>
</xsl:stylesheet>
如果将此更正的转换应用于同一个XML文档(上图),则会生成所需的正确结果。
<强> III。分析我发现的错误:
...
<xsl:key name="kValues" match="p"
use="generate-id[preceding::li[1]]"/>
...
此处任何p
元素都由其generate-id
子项的字符串值编制索引,其前缀为li
。
但是,XML文档中没有名为generate-id
的元素。
真正意图是使用generate-id()
功能。函数调用由函数名称组成,后跟一系列实际参数值,用常规圆括号(
和)
括起来。用方括号替换圆括号从根本上改变了表达式的语义,将函数调用转换为(相对)位置步骤。
0.2。 :此强>:
<xsl:variable name="vValues">
<xsl:value-of select="key('kValues',generate-id())"/>
</xsl:variable>
不仅是一种(非常)不良做法,而且往往是导致错误,就像在当前案例中一样。您正在创建树(文档节点),而不是元素的节点集。树总是至少有一个节点(文档节点)及其布尔值,因此始终为真。
永远不要使用上面的语法。
正确的变量声明是:
<xsl:variable name="vValues" select="key('kValues',generate-id())"/>
0.3。没有模板规则可以阻止身份模板复制任何不需要的ul
,p
和text()
节点,这些规则会出现在原始转换的结果中。