如何使用 XSLT 从平面 xml 文件创建 html 列表

发布于 2024-09-27 08:24:06 字数 1518 浏览 6 评论 0原文

我正在寻找一种干净的方法来使用 XSLT 执行以下操作。

转换此源:

<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<list>num3</list>
<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<para>blah blah blah blah blah</para>

到此输出:

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

请记住,我不知道到底有多少

到目前为止我有这个:

<xsl:template match="para">
    <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="list">
    <ol><li><xsl:value-of select="." /></li></ol>
</xsl:template>

但我的输出看起来像这样:

<p>blah blah</p>    
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<ol><li>num3</li></ol>
<p>blah blah</p>
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<p>blah blah blah blah blah</p>

我知道为什么我得到重复的

    元素,但我不知道如何阻止它。真是一个脑筋急转弯。

任何帮助将不胜感激。

I am looking for a clean way to do the following using XSLT.

Convert this source:

<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<list>num3</list>
<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<para>blah blah blah blah blah</para>

To this output:

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

Keep in mind I do not know exactly how many <list>'s there will be.

So far I have this:

<xsl:template match="para">
    <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="list">
    <ol><li><xsl:value-of select="." /></li></ol>
</xsl:template>

But my output looks like this:

<p>blah blah</p>    
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<ol><li>num3</li></ol>
<p>blah blah</p>
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<p>blah blah blah blah blah</p>

I know why I am getting duplicate <ol> elements, but I do not know how to stop it. Quite a brain teaser.

Any help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如痴如狂 2024-10-04 08:24:06

XSLT 2.0 有专门用于此类操作的工具:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="xml">
        <xsl:for-each-group select="*" group-adjacent="boolean(self::list)">
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <ol>
                        <xsl:apply-templates select="current-group()"/>
                    </ol>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>
    <xsl:template match="list">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
</xsl:stylesheet>

使用此 XML:

<xml>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</xml>

您将获得所需的输出:

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

您应该在 http://www.w3.org/TR/xslt20/#xsl-for-each-group

XSLT 2.0 has tools especially for this kind of Operations:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="xml">
        <xsl:for-each-group select="*" group-adjacent="boolean(self::list)">
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <ol>
                        <xsl:apply-templates select="current-group()"/>
                    </ol>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>
    <xsl:template match="list">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
</xsl:stylesheet>

With this XML:

<xml>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</xml>

You'll get the desired Output:

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

You should read up on for-each-group at http://www.w3.org/TR/xslt20/#xsl-for-each-group

橪书 2024-10-04 08:24:06

此 XSLT 1.0 样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()">
        <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:value-of select="."/>
        </p>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="list[preceding-sibling::node()[1][not(self::list)]]">
        <ol>
            <xsl:call-template name="makeList"/>
        </ol>
        <xsl:apply-templates select="following-sibling::node()
                                              [not(self::list)][1]"/>
    </xsl:template>
    <xsl:template match="list" name="makeList">
        <li>
            <xsl:value-of select="."/>
        </li>
        <xsl:apply-templates select="following-sibling::node()[1]
                                              [self::list]"/>
    </xsl:template>
</xsl:stylesheet>

输出:

<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

注意: 细粒度遍历。

编辑:紧凑的代码。

This XSLT 1.0 stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()">
        <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:value-of select="."/>
        </p>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="list[preceding-sibling::node()[1][not(self::list)]]">
        <ol>
            <xsl:call-template name="makeList"/>
        </ol>
        <xsl:apply-templates select="following-sibling::node()
                                              [not(self::list)][1]"/>
    </xsl:template>
    <xsl:template match="list" name="makeList">
        <li>
            <xsl:value-of select="."/>
        </li>
        <xsl:apply-templates select="following-sibling::node()[1]
                                              [self::list]"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

Note: Fine grained traversal.

Edit: Compact code.

哆兒滾 2024-10-04 08:24:06

此转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kFollowing" match="list"
  use="generate-id(preceding-sibling::para[1])"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="para">
  <p>
    <xsl:apply-templates/>
  </p>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

当应用于以下 XML 文档时(将提供的输入包装在单个顶部元素中):

<t>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</t>

产生所需的正确结果

<t>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <p>blah blah blah blah blah</p>
</t>

更新:OP在评论中表示,现在他想要一个解决方案,其中任何列表元素都可以分隔一组相邻的列出兄弟姐妹。

这是更改后的问题的解决方案

<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="list"
  use="generate-id(preceding-sibling::*[not(self::list)][1])"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*[not(self::list) and following-sibling::*[1][self::list]]">
  <xsl:call-template name="identity"/>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时(请注意,分隔元素现在具有随机名称):

<t>
    <bara>blah blah</bara>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <vara>blah blah</vara>
    <list>num1</list>
    <list>num2</list>
    <dara>blah blah blah blah blah</dara>
</t>

想要的,产生正确的结果

<t>
    <bara>blah blah</bara>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <vara>blah blah</vara>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <dara>blah blah blah blah blah</dara>
</t>

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kFollowing" match="list"
  use="generate-id(preceding-sibling::para[1])"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="para">
  <p>
    <xsl:apply-templates/>
  </p>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

when applied on the following XML document (wrapping the provided input in a single top element):

<t>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</t>

produces the wanted, correct result:

<t>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <p>blah blah blah blah blah</p>
</t>

UPDATE: The OP has indicated in a comment that now he wants a solution where any non-list element can delimit a group of adjacent list siblings.

Here is the solution to the changed question :

<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="list"
  use="generate-id(preceding-sibling::*[not(self::list)][1])"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*[not(self::list) and following-sibling::*[1][self::list]]">
  <xsl:call-template name="identity"/>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

When this transformation is applied on the following XML document (Note that the separating elements have now random names):

<t>
    <bara>blah blah</bara>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <vara>blah blah</vara>
    <list>num1</list>
    <list>num2</list>
    <dara>blah blah blah blah blah</dara>
</t>

the wanted, correct result is produced:

<t>
    <bara>blah blah</bara>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <vara>blah blah</vara>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <dara>blah blah blah blah blah</dara>
</t>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文