如何在 XSLT 的前兄弟中测试多个条件
How to test for multiple conditions in previous-sibling in XSLT
我有 XML 数据是从遗留的 Lotus Notes 应用程序中提取的,并且嵌入了富文本格式。我试图根据出现在前一个兄弟姐妹中的属性来格式化每个文本块。我的 XSLT 受到来自@Jayvee 的 的启发,但它不起作用。
这是XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<item name="Unordered list">
<richtext>
<pardef/>
<par def="20">
<run>This is the first </run><run>paragraph of the preamble.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>preamble.</run>
</par>
<pardef id="21" list="unordered"/>
<par def="21">
<run>This is the </run><run>first bullet.</run>
</par>
<par>
<run>This is the second </run><run>bullet.</run>
</par>
<par def="20">
<run>This is the first </run><run>paragraph of the conclusion.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>conclusion.</run>
</par>
</richtext>
</item>
<item name="Ordered list">
<richtext>
<pardef/>
<par def="20">
<run>This is the first </run><run>paragraph of the preamble.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>preamble.</run>
</par>
<pardef id="46" list="ordered"/>
<par def="46">
<run>This is the </run><run>first numbered item.</run>
</par>
<par>
<run>This is the another </run><run>numbered item.</run>
</par>
<par def="20">
<run>This is the first </run><run>paragraph of the conclusion.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>conclusion.</run>
</par>
</richtext>
</item>
</document>
这是期望的输出:
<html>
<body>
<table border="1">
<tr>
<td>Unordered list</td>
<td>
<p>This is the first paragraph of the preamble.</p>
<p>This is the second paragraph of the preamble.</p>
<ul>
<li>This is the first bullet.</li>
<li>This is the second bullet.</li>
</ul>
<p>This is the first paragraph of the conclusion.</p>
<p>This is the second paragraph of the conclusion.</p>
</td>
</tr>
<tr>
<td>Ordered list</td>
<td>
<p>This is the first paragraph of the preamble.</p>
<p>This is the second paragraph of the preamble.</p>
<ol>
<li>This is the first numbered item.</li>
<li>This is the another numbered item.</li>
</ol>
<p>This is the first paragraph of the conclusion.</p>
<p>This is the second paragraph of the conclusion.</p>
</td>
</tr>
</table>
</body>
这是 XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/*">
<html>
<body>
<table border="1">
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td>
<xsl:apply-templates/>
</td>
</tr>
</xsl:template>
<xsl:template match="par">
<xsl:choose>
<xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"></ul></xsl:text></xsl:when>
<xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"></ol></xsl:text></xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="@def=preceding-sibling::pardef[@id] or (not(@def) and preceding-sibling::par[@def][1][@def=preceding-sibling::pardef[@id]])">
<xsl:choose>
<xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"><ul></xsl:text></xsl:when>
<xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"><ol></xsl:text></xsl:when>
</xsl:choose>
<li>
<xsl:for-each select="run">
<xsl:value-of select="text()" separator=""/>
</xsl:for-each>
</li>
</xsl:when>
<xsl:when test="not(@def=preceding-sibling::pardef[@id])">
<p>
<xsl:for-each select="run">
<xsl:value-of select="text()" separator=""/>
</xsl:for-each>
</p>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
上一题中的做法是disable-output-escaping
输出开始和结束标签,这不是一个理想的做法。
相反,考虑使用一个键将 par
个元素组合在一起,第一个 par
元素具有 def
属性
<xsl:key name="pars"
match="par[not(@def)]"
use="generate-id(preceding-sibling::par[@def][1])" />
而且,假设您在 par
元素上匹配 def
属性,您可以像这样使用键:
<xsl:variable name="group" select="self::* | key('pars', generate-id())" />
要确定是否将组包装在 ul
或 ol
标记中,您可以按如下方式获取列表类型:
<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
然后您可以对此进行测试以确定是否将组包装在列表标记中。
试试这个 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:key name="pars" match="par[not(@def)]" use="generate-id(preceding-sibling::par[@def][1])" />
<xsl:template match="/*">
<html>
<body>
<table border="1">
<xsl:apply-templates />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td>
<xsl:apply-templates select="richtext/par[@def]" />
</td>
</tr>
</xsl:template>
<xsl:template match="par[@def]">
<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
<xsl:variable name="group" select="self::* | key('pars', generate-id())" />
<xsl:choose>
<xsl:when test="$listType = 'unordered'">
<ol>
<xsl:apply-templates select="$group" mode="list"/>
</ol>
</xsl:when>
<xsl:when test="$listType = 'ordered'">
<ul>
<xsl:apply-templates select="$group" mode="list"/>
</ul>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$group" mode="para" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="par" mode="list">
<li>
<xsl:value-of select="run" separator=""/>
</li>
</xsl:template>
<xsl:template match="par" mode="para">
<para>
<xsl:value-of select="run" separator=""/>
</para>
</xsl:template>
</xsl:stylesheet>
我有 XML 数据是从遗留的 Lotus Notes 应用程序中提取的,并且嵌入了富文本格式。我试图根据出现在前一个兄弟姐妹中的属性来格式化每个文本块。我的 XSLT 受到来自@Jayvee 的
这是XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<item name="Unordered list">
<richtext>
<pardef/>
<par def="20">
<run>This is the first </run><run>paragraph of the preamble.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>preamble.</run>
</par>
<pardef id="21" list="unordered"/>
<par def="21">
<run>This is the </run><run>first bullet.</run>
</par>
<par>
<run>This is the second </run><run>bullet.</run>
</par>
<par def="20">
<run>This is the first </run><run>paragraph of the conclusion.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>conclusion.</run>
</par>
</richtext>
</item>
<item name="Ordered list">
<richtext>
<pardef/>
<par def="20">
<run>This is the first </run><run>paragraph of the preamble.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>preamble.</run>
</par>
<pardef id="46" list="ordered"/>
<par def="46">
<run>This is the </run><run>first numbered item.</run>
</par>
<par>
<run>This is the another </run><run>numbered item.</run>
</par>
<par def="20">
<run>This is the first </run><run>paragraph of the conclusion.</run>
</par>
<par>
<run>This is the second paragraph of the </run><run>conclusion.</run>
</par>
</richtext>
</item>
</document>
这是期望的输出:
<html>
<body>
<table border="1">
<tr>
<td>Unordered list</td>
<td>
<p>This is the first paragraph of the preamble.</p>
<p>This is the second paragraph of the preamble.</p>
<ul>
<li>This is the first bullet.</li>
<li>This is the second bullet.</li>
</ul>
<p>This is the first paragraph of the conclusion.</p>
<p>This is the second paragraph of the conclusion.</p>
</td>
</tr>
<tr>
<td>Ordered list</td>
<td>
<p>This is the first paragraph of the preamble.</p>
<p>This is the second paragraph of the preamble.</p>
<ol>
<li>This is the first numbered item.</li>
<li>This is the another numbered item.</li>
</ol>
<p>This is the first paragraph of the conclusion.</p>
<p>This is the second paragraph of the conclusion.</p>
</td>
</tr>
</table>
</body>
这是 XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/*">
<html>
<body>
<table border="1">
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td>
<xsl:apply-templates/>
</td>
</tr>
</xsl:template>
<xsl:template match="par">
<xsl:choose>
<xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"></ul></xsl:text></xsl:when>
<xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] != preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"></ol></xsl:text></xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="@def=preceding-sibling::pardef[@id] or (not(@def) and preceding-sibling::par[@def][1][@def=preceding-sibling::pardef[@id]])">
<xsl:choose>
<xsl:when test="preceding-sibling::pardef[@list] = 'unordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"><ul></xsl:text></xsl:when>
<xsl:when test="preceding-sibling::pardef[@list] = 'ordered' and preceding-sibling::par[@def][1][@def] = preceding-sibling::pardef[@id]"><xsl:text disable-output-escaping="yes"><ol></xsl:text></xsl:when>
</xsl:choose>
<li>
<xsl:for-each select="run">
<xsl:value-of select="text()" separator=""/>
</xsl:for-each>
</li>
</xsl:when>
<xsl:when test="not(@def=preceding-sibling::pardef[@id])">
<p>
<xsl:for-each select="run">
<xsl:value-of select="text()" separator=""/>
</xsl:for-each>
</p>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
上一题中的做法是disable-output-escaping
输出开始和结束标签,这不是一个理想的做法。
相反,考虑使用一个键将 par
个元素组合在一起,第一个 par
元素具有 def
属性
<xsl:key name="pars"
match="par[not(@def)]"
use="generate-id(preceding-sibling::par[@def][1])" />
而且,假设您在 par
元素上匹配 def
属性,您可以像这样使用键:
<xsl:variable name="group" select="self::* | key('pars', generate-id())" />
要确定是否将组包装在 ul
或 ol
标记中,您可以按如下方式获取列表类型:
<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
然后您可以对此进行测试以确定是否将组包装在列表标记中。
试试这个 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:key name="pars" match="par[not(@def)]" use="generate-id(preceding-sibling::par[@def][1])" />
<xsl:template match="/*">
<html>
<body>
<table border="1">
<xsl:apply-templates />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td>
<xsl:apply-templates select="richtext/par[@def]" />
</td>
</tr>
</xsl:template>
<xsl:template match="par[@def]">
<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
<xsl:variable name="group" select="self::* | key('pars', generate-id())" />
<xsl:choose>
<xsl:when test="$listType = 'unordered'">
<ol>
<xsl:apply-templates select="$group" mode="list"/>
</ol>
</xsl:when>
<xsl:when test="$listType = 'ordered'">
<ul>
<xsl:apply-templates select="$group" mode="list"/>
</ul>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$group" mode="para" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="par" mode="list">
<li>
<xsl:value-of select="run" separator=""/>
</li>
</xsl:template>
<xsl:template match="par" mode="para">
<para>
<xsl:value-of select="run" separator=""/>
</para>
</xsl:template>
</xsl:stylesheet>