【问题标题】:XSL XPath select mixed text and node in order within for-each loop?XSL XPath 在 for-each 循环中按顺序选择混合文本和节点?
【发布时间】:2016-10-09 12:26:38
【问题描述】:

我正在尝试使用 XSL 将 XML 文档转换为 HTML 页面。我已经完成了 95%,但是我遇到了包含文本和其他必须按顺序显示的节点的节点的问题。

XML:

<chapter title="Chapter 1" reqlen="2500">
    <section title="The Quick Brown Fox">
        <subsection title="null">
            <keywords>foo,bar</keywords>
            <body>
                <p>
                    Lorem ipsum <b>dolor sit amet</b>, consectetur adipiscing elit. 
        Maecenas sed pretium nunc.
                    <int>foo/bar/qux</int>
                    Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
                    <ext>http://google.com/</ext>
                </p>
                <p>
                    Foo bar <b>doqux amet</b>, foo adipiscing elit. 
        Maecenas sed pretium nunc.
                    <int>foo/bar/qux</int>
                    Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
                    <ext>http://google.com/</ext>
                </p>
            </body>
            <note>Lorem ipsum</note>
        </subsection>
    </section>
</chapter>

XSL:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="stylesheet" version="1.0">
    <xsl:template match="xsl:stylesheet" />
    <xsl:template match="/chapter">
        <html>
            <head>
                <title>
                    <xsl:value-of select="@title" />
                </title>
                <style type="text/css">body {
            padding: 50px 10%;
          }</style>
            </head>
            <body>
                <h1>
                    <xsl:value-of select="@title" />
                </h1>
                <xsl:for-each select="section">
                    <xsl:if test="@title!='null'">
                        <h2>
                            <xsl:value-of select="@title" />
                        </h2>
                    </xsl:if>
                    <xsl:for-each select="subsection">
                        <xsl:if test="@title!='null'">
                            <h3>
                                <xsl:value-of select="@title" />
                            </h3>
                        </xsl:if>
                        <xsl:for-each select="body/p">
                            <p>
                                <xsl:value-of select="current()" />
                            </p>
                        </xsl:for-each>
                    </xsl:for-each>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

这会产生以下 HTML:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Chapter 1</title>
        <style type="text/css">
            body {
            padding: 50px 10%;
            }
        </style>
    </head>
    <body>
        <h1>Chapter 1</h1>
        <h2>The Quick Brown Fox</h2>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Maecenas sed pretium nunc.
            foo/bar/qux
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            http://google.com/
        </p>
        <p>
            Foo bar doqux amet, foo adipiscing elit.
            Maecenas sed pretium nunc.
            foo/bar/qux
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            http://google.com/
        </p>
    </body>
</html>

问题是,我正在尝试转换 &lt;p&gt;&lt;/p&gt; 节点中的某些标签。

&lt;p&gt; 节点内部,可以混合有纯文本和节点&lt;b&gt;&lt;/b&gt;&lt;i&gt;&lt;/i&gt;&lt;int&gt;&lt;/int&gt;&lt;ext&gt;&lt;/ext&gt;&lt;cvc&gt;&lt;/cvc&gt;。永远不会有超出此级别的嵌套,即 &lt;b&gt;&lt;/b&gt; 将永远包含文本。

这是我想要的 HTML:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Chapter 1</title>
        <style type="text/css">
            body {
            padding: 50px 10%;
            }
        </style>
    </head>
    <body>
        <h1>Chapter 1</h1>
        <h2>The Quick Brown Fox</h2>
        <p>
            Lorem ipsum <strong>dolor sit amet</strong>, consectetur adipiscing elit.
            Maecenas sed pretium nunc.
            <a href="/foo/bar/qux">foo/bar/qux</a>
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            <a href="http://google.com/">http://google.com/</a>
        </p>
        <p>Foo bar <strong>doqux amet</strong>, foo adipiscing elit. 
            Maecenas sed pretium nunc.
            <a href="/foo/bar/qux">foo/bar/qux</a>
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            <a href="http://google.com/">http://google.com/</a>
        </p>
    </body>
</html>

我尝试了不同的 XPath 函数、for-each 循环以及两者的混合,但我不知道如何获得我想要的输出。我得到的最接近的是这个 XSL:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="stylesheet" version="1.0">
    <xsl:template match="xsl:stylesheet" />
    <xsl:template match="/chapter">
        <html>
            <head>
                <title>
                    <xsl:value-of select="@title" />
                </title>
                <style type="text/css">body {
            padding: 50px 10%;
          }</style>
            </head>
            <body>
                <h1>
                    <xsl:value-of select="@title" />
                </h1>
                <xsl:for-each select="section">
                    <xsl:if test="@title!='null'">
                        <h2>
                            <xsl:value-of select="@title" />
                        </h2>
                    </xsl:if>
                    <xsl:for-each select="subsection">
                        <xsl:if test="@title!='null'">
                            <h3>
                                <xsl:value-of select="@title" />
                            </h3>
                        </xsl:if>
                        <xsl:for-each select="body/p">
                            <p>
                                <xsl:for-each select="text()">
                                    <xsl:value-of select="current()" />
                                </xsl:for-each>
                                <xsl:for-each select="b">
                                    <strong>
                                        <xsl:value-of select="current()" />
                                    </strong>
                                </xsl:for-each>
                                <xsl:for-each select="int">
                                    <a href="#">
                                        <xsl:value-of select="current()" />
                                    </a>
                                </xsl:for-each>
                                <xsl:for-each select="ext">
                                    <a href="#">
                                        <xsl:value-of select="current()" />
                                    </a>
                                </xsl:for-each>
                            </p>
                        </xsl:for-each>
                    </xsl:for-each>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

但是 HTML 输出是乱序的:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Chapter 1</title>
        <style type="text/css">
            body {
            padding: 50px 10%;
            }
        </style>
    </head>
    <body>
        <h1>Chapter 1</h1>
        <h2>The Quick Brown Fox</h2>
        <p>
            Lorem ipsum , consectetur adipiscing elit.
            Maecenas sed pretium nunc.
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            <strong>dolor sit amet</strong><a href="#">foo/bar/qux</a><a href="#">http://google.com/</a>
        </p>
        <p>
            Foo bar , foo adipiscing elit.
            Maecenas sed pretium nunc.
            Proin tincidunt sapien dolor, posuere varius dui efficitur ac.
            <strong>doqux amet</strong><a href="#">foo/bar/qux</a><a href="#">http://google.com/</a>
        </p>
    </body>
</html>

【问题讨论】:

  • 您需要学习如何使用模板规则。使用模板规则递归处理 XML 树是使用 XSLT 的自然方式,对于处理混合内容尤其重要。

标签: html xml xslt xpath


【解决方案1】:

考虑这样的事情:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="xsl:stylesheet" />
  <xsl:template match="/chapter">
    <html>
      <head>
        <title>
          <xsl:value-of select="@title" />
        </title>
        <style type="text/css">
          body {
          padding: 50px 10%;
          }
        </style>
      </head>
      <body>
        <h1>
          <xsl:value-of select="@title" />
        </h1>
        <xsl:for-each select="section">
          <xsl:if test="@title!='null'">
            <h2>
              <xsl:value-of select="@title" />
            </h2>
          </xsl:if>
          <xsl:for-each select="subsection">
            <xsl:if test="@title!='null'">
              <h3>
                <xsl:value-of select="@title" />
              </h3>
            </xsl:if>
            <xsl:for-each select="body/p">
              <p>
                <xsl:apply-templates/>
              </p>
            </xsl:for-each>
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>


  <xsl:template match="b">
    <strong>
      <xsl:value-of select="."/>
    </strong>
  </xsl:template>

  <xsl:template match="int">
    <a href="#">
      <xsl:value-of select="."/>
    </a>
  </xsl:template>

  <xsl:template match="ext">
    <a href="#">
      <xsl:value-of select="."/>
    </a>
  </xsl:template>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多