【发布时间】: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>
问题是,我正在尝试转换 <p></p> 节点中的某些标签。
在<p> 节点内部,可以混合有纯文本和节点<b></b>、<i></i>、<int></int>、<ext></ext> 和<cvc></cvc>。永远不会有超出此级别的嵌套,即 <b></b> 将永远包含文本。
这是我想要的 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 的自然方式,对于处理混合内容尤其重要。