Xml XSLT用匹配规则替换条件逻辑
我有一个XSLT样式表,它以错误的顺序调用模板。它不是按段落和表格的显示顺序呈现段落和表格,而是呈现所有段落,然后是所有表格。我猜这个问题可以通过用模式匹配代替条件逻辑来解决,但我很难弄清楚如何做到这一点 完整的XSLT如下所示:Xml XSLT用匹配规则替换条件逻辑,xml,xslt,Xml,Xslt,我有一个XSLT样式表,它以错误的顺序调用模板。它不是按段落和表格的显示顺序呈现段落和表格,而是呈现所有段落,然后是所有表格。我猜这个问题可以通过用模式匹配代替条件逻辑来解决,但我很难弄清楚如何做到这一点 完整的XSLT如下所示: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes" method="html"/>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes" method="html"/>
<xsl:template match="/*">
<html>
<head></head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="richtext">
<xsl:if test="par">
<xsl:apply-templates select="." mode="par" />
</xsl:if>
<xsl:if test="table">
<xsl:apply-templates select="." mode="table" />
</xsl:if>
</xsl:template>
<xsl:template match="richtext" mode="par">
<xsl:for-each-group select="par[run[normalize-space()]]" group-adjacent="if (@def) then @def else preceding-sibling::par[run[normalize-space()]][@def][1]/@def">
<xsl:variable name="listType" select="preceding-sibling::*[1][self::pardef]/@list" />
<xsl:choose>
<xsl:when test="$listType = 'bullet'">
<ul>
<xsl:apply-templates select="current-group()" mode="list"/>
</ul>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()" mode="para" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="richtext" mode="table">
<table border="1">
<xsl:for-each select="table/tablerow">
<tr>
<xsl:for-each select="tablecell">
<td>
<xsl:apply-templates />
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="par" mode="list">
<li>
<xsl:apply-templates select="run" />
</li>
</xsl:template>
<xsl:template match="par" mode="para">
<p>
<xsl:apply-templates select="run" />
</p>
</xsl:template>
<xsl:template match="run">
<xsl:value-of select="text()" separator=""/>
</xsl:template>
</xsl:stylesheet>
以下是XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<item name="Some richtext">
<richtext>
<pardef/>
<par def="20">
<run>This is a </run>
<run>paragraph.</run>
</par>
<table>
<tablerow>
<tablecell>
<par def="43"><run>This is a table</run></par></tablecell>
<tablecell>
<par def="44"><run>This is some data</run></par></tablecell>
</tablerow>
</table>
<pardef id="21" list="bullet"/>
<par def="21">
<run>This is a </run>
<run>bullet point.</run>
</par>
<table>
<tablerow>
<tablecell>
<par def="43"><run>This is another table</run></par></tablecell>
<tablecell>
<par def="44"><run>This is some data</run></par></tablecell>
</tablerow>
</table>
</richtext>
</item>
</document>
这是一个
段落
这是一张桌子
这是一些数据
这是一个
要点。
这是另一张桌子
这是一些数据
这是我想要的输出:
<html>
<head></head>
<body>
<p>This is a paragraph.</p>
<table border="1">
<tr>
<td>This is a table</td>
<td>This is some data</td>
</tr>
</table>
<ul>
<li>This is a bullet point.</li>
</ul>
<table border="1">
<tr>
<td>This is another table</td>
<td>This is some data</td>
</tr>
</table>
</body>
</html>
这是一段
这是一张桌子
这是一些数据
- 这是一个要点
这是另一张桌子
这是一些数据
您的许多问题似乎都是由于试图使用@mode来完成@match的工作而造成的。一个好的经验法则是避免@mode,除非您可能多次处理同一个节点或节点类型,或者希望在不同的时间做不同的事情
正如@michael.hor257k所说,最好让apply模板为您进行逻辑选择
另外,您的测试也有点不可靠,只是查看是否存在richtext的table/par子级,而不是当前上下文节点是什么(这是应用模板已经为您做的):对于您的示例,xsl:if语句都是true
下面是一些XSLT,它可以从输入中创建您想要的内容(使用XHTML而不是HTML):我最终使用了一种模式来区分列表和普通段落,但这符合上面的经验法则:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:local="http://example.com/local"
exclude-result-prefixes="xs local"
version="2.0">
<xsl:output indent="yes" method="xhtml"/>
<xsl:strip-space elements="*"/>
<xsl:key name="pars" match="par" use="preceding-sibling::pardef[1]/generate-id()"/>
<xsl:template match="document">
<html>
<head/>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- I want to handle par using modes, so I deliberately remove any output in the default mode. We'll make an exception for par in table later. -->
<xsl:template match="par"/>
<xsl:template match="pardef[not(@list)]">
<!-- I'm using a key() function here just to easily return the par elements that follow this pardef
- see the xsl:key definition above. You could also try using @id and @def e.g.
<key name="pars" match="par" use="@def"/>
and key('pars', @id) - although the first @id in your example seems to be missing!
-->
<xsl:apply-templates select="key('pars', generate-id())" mode="p"/>
</xsl:template>
<xsl:template match="pardef[@list]">
<ul>
<xsl:apply-templates select="key('pars', generate-id())" mode="li"/>
</ul>
</xsl:template>
<xsl:template match="par" mode="p">
<p>
<!-- Any further elements don't need mode handling, so we'll return to the default mode -->
<xsl:apply-templates mode="#default"/>
</p>
</xsl:template>
<xsl:template match="par" mode="li">
<li>
<xsl:apply-templates mode="#default"/>
</li>
</xsl:template>
<xsl:template match="table">
<table border="1">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="tablerow">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="tablecell/par">
<td>
<xsl:apply-templates/>
</td>
</xsl:template>
</xsl:stylesheet>
如果有人能告诉我为什么我必须使用generate-id()而不是just。在关键函数和定义中,我想知道-我认为这可能是我的Saxon(9.6.0.7)中的一个bug。老实说,这不是一个代码编写服务。你最后的9个!问题是关于同一主题的。它总是能解决给定的问题,但不能概括地解决您的项目。学习XSLT以理解给定的解决方案,而不仅仅是复制粘贴它们。我认为版主需要调查。问题实际上不是你的条件逻辑,而是带有模式“par”的模板如何工作。如果您编辑问题以显示此模板,以及“表格”模板(我知道它在前面的问题中,但问题应该是自包含的),可能会有所帮助。谢谢。嗨@uL,我其实不是新手——我在2003-2005年广泛使用XSLT,几年前又一次使用XSLT——但我变得生疏了,因为我不总是这样做。这可能并不明显,但我一直在研究答案,试图理解它们。感谢大家在我努力跟上进度时对我的支持。@b00kgrrl我不明白为什么这里需要条件逻辑。只需将模板应用到
par
和table
中,并为每个模板创建一个模板即可。这是一个非常优雅的解决方案。谢谢@yamahito,如果您在键定义中使用了use=“.”
,那么对于所有空pardef
元素,将使用空
的字符串值,并且将是相同的值,即空字符串。你没有说你得到了哪个结果,但是我不认为对几个pardef
元素使用相同的值会对你的算法起作用。啊,这是字符串值。出于某种原因,我记错了在2中会使用与“is”比较器等效的东西。总是有新的东西要学!