我在XML文件中有几个无序列表,我需要使用XSL文件将其转换为HTML。 XML内的这些列表如下所示:
<Food>
<FoodItem ID="1">
<Content><![CDATA[<ul><li>Apples</li><li>Pears</li><li>Oranges</li><ul>]]></Content>
</FoodItem>
</Food>
我想从XML文件中获取无序列表,然后将其输出到我的XSL文件中,这样我就可以使用CSS对其进行样式化。结果应该是这样的:
<div class="food">
<ul class="fooditems">
<li class="fooditem">Apples</li>
<li class="fooditem">Pears</li>
<li class="fooditem">Oranges</li>
</ul>
</div>
但是,<xsl:value-of select="key('fooditem', 1)/Content
只给了我一个字符串<ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>
。
密钥定义为<xsl:key name="fooditem" match="FoodItem" use="@ID" />
。
如何从<![CDATA[]]>
标签中获取包括其内容在内的各个列表标签?
答案 0 :(得分:1)
如何从标签中获取各个列表标签及其内容?
对于XSLT-1.0解决方案,您必须使用两步方法:
一个问题是CDATA示例不是格式正确的 XML。因此,您必须将输入XML(将最后一个<ul>
更改为</ul>
)更改为以下内容:
<Food>
<FoodItem ID="1">
<Content><![CDATA[<ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>]]></Content>
</FoodItem>
</Food>
对于第一步,您可以使用它(假设您的XSLT处理器确实支持disable-output-escaping属性):
<?xml version="1.0" encoding="utf-8"?>
<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"/>
<!-- Identity template -->
<xsl:template match="node()[not(self::text())]|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>
</xsl:stylesheet>
现在,您可以将XSLT模板应用于上述样式表的输出。
此转换的结果应为:
<?xml version="1.0" encoding="UTF-8"?>
<Food>
<FoodItem ID="1">
<Content>
<ul>
<li>Apples</li>
<li>Pears</li>
<li>Oranges</li>
<ul>
</Content>
</FoodItem>
</Food>
现在,第二步是将不同的XSLT-1.0样式表应用于此输出。
因此,应用第二个XSLT-1.0样式表:
<?xml version="1.0" encoding="utf-8"?>
<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="/Food/FoodItem/Content/ul">
<div class="food">
<ul class="fooditems">
<xsl:apply-templates select="*" />
</ul>
</div>
</xsl:template>
<xsl:template match="li">
<li class="fooditem"><xsl:value-of select="." /></li>
</xsl:template>
</xsl:stylesheet>
第二步的结果是:
<div class="food">
<ul class="fooditems">
<li class="fooditem">Apples</li>
<li class="fooditem">Pears</li>
<li class="fooditem">Oranges</li>
</ul>
</div>
这是所需的。
使用更新版本的XSLT处理器(3.0及更高版本),您可以(可能)在一个样式表中完成两个步骤。
答案 1 :(得分:1)
首先,ul
/ li
元素不是输入XML中的节点,而是CDATA部分中的转义标记。因此,您需要先解析该标记,然后才能转换节点。使用XSLT 3(由Saxon 9.8和更高版本或AltovaXML 2017和更高版本支持),您可以使用parse-xml
或parse-xml-fragment
XPath 3函数将带有XML文档或XML片段的字符串解析为节点。
但是,至少在您的问题示例中,转义的标记不是格式正确的XML,因为它没有正确关闭的ul
元素,应在<ul><li>Apples</li><li>Pears</li><li>Oranges</li><ul>
处{{ 1}}可以解析为XML。
因此,根据实际示例,如果格式正确,则可以使用
<ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>
如https://xsltfiddle.liberty-development.net/3NJ38ZH/1所示,并获得所需的输出
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:template match="FoodItem">
<div class="food">
<xsl:apply-templates select="parse-xml-fragment(Content)/node()" mode="food"/>
</div>
</xsl:template>
<xsl:mode name="food" on-no-match="shallow-copy"/>
<xsl:template match="ul" mode="food">
<ul class="fooditems">
<xsl:apply-templates select="@* , node()" mode="#current"/>
</ul>
</xsl:template>
<xsl:template match="li" mode="food">
<li class="fooditem">
<xsl:apply-templates select="@* , node()" mode="#current"/>
</li>
</xsl:template>
</xsl:stylesheet>