如何将XML中的<ul>和<li>元素输出到XSL?

时间:2019-06-08 21:59:23

标签: xml xslt

我在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[]]>标签中获取包括其内容在内的各个列表标签?

2 个答案:

答案 0 :(得分:1)

  

如何从标签中获取各个列表标签及其内容?

对于XSLT-1.0解决方案,您必须使用两步方法:

  1. 从CDATA部分获取项目。
  2. 应用您要应用的模板。

一个问题是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-xmlparse-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>