XSL XPath在for-each循环中按顺序选择混合文本和节点?

时间:2016-06-09 02:45:13

标签: html xml xslt xpath

我正在尝试使用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>

问题是,我正在尝试转换<p></p>个节点内的某些标签。

<p>个节点内,可以混合使用纯文本和节点<b></b><i></i><int></int><ext></ext>和{{ 1}}。永远不会嵌套超出此级别,即<cvc></cvc>只会包含文本。

这是我想要的HTML:

<b></b>

我尝试了不同的XPath函数,<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> 循环以及两者的混合,但我无法弄清楚如何获得我想要的输出。我最接近的是这个XSL:

for-each

但HTML输出乱序:

<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>

1 个答案:

答案 0 :(得分: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>