如何使XSLT模板处理缺少的父元素?
我想为这个糟糕的标题道歉——我真的不知道如何更好地表达它。我目前正在编写XSLT1.0脚本(使用),该脚本将简单的XML格式转换为适合PDF生成器使用的文本表示形式 在我的XML格式中,只有三个元素:如何使XSLT模板处理缺少的父元素?,xslt,Xslt,我想为这个糟糕的标题道歉——我真的不知道如何更好地表达它。我目前正在编写XSLT1.0脚本(使用),该脚本将简单的XML格式转换为适合PDF生成器使用的文本表示形式 在我的XML格式中,只有三个元素:、和。然而,由于DTD的一些讨厌的特性,我很难编写一个合适的XSLT脚本来转换文档。以下是描述其关系的DTD: <!ELEMENT book ((chapter|section)*)> <!ELEMENT chapter (section*)> <!ELEMENT se
、
和
。然而,由于DTD的一些讨厌的特性,我很难编写一个合适的XSLT脚本来转换文档。以下是描述其关系的DTD:
<!ELEMENT book ((chapter|section)*)>
<!ELEMENT chapter (section*)>
<!ELEMENT section (#PCDATA)>
因此,我想做的是调整XSLT脚本,以便在给定的
元素不在
中时,“section”模板也以某种方式调用“chapter”模板。我怎么能这样做
值得一提的是,这里还有一个例子。一个
中不存在的多个
元素应合并为一个。因此,
产生三章的输出(第一章有三个章节,第二章没有,第三章有一个章节)。您需要首先将孤立章节包装成一章
我们为此创建一个变量来保存包装的元素
<xsl:variable name="orphan">
<chapter>
<xsl:for-each select="/book/section">
<xsl:copy-of select="." />
</xsl:for-each>
</chapter>
</xsl:variable>
要使用exslt
,您需要添加名称空间
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common">
最终结果是
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common">
<xsl:output method="html" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="orphan">
<chapter>
<xsl:for-each select="/book/section">
<xsl:copy-of select="." />
</xsl:for-each>
</chapter>
</xsl:variable>
<xsl:template match="section">
<xsl:if test="not(preceding-sibling::section)">@BeginSections
</xsl:if>
<xsl:text>@Section @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text>@End @Section
</xsl:text>
<xsl:if test="not(following-sibling::section)">@EndSections
</xsl:if>
</xsl:template>
<xsl:template match="chapter">
<xsl:if test="not(preceding-sibling::chapter)">@BeginChapters
</xsl:if>
<xsl:text>@Chapter @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text>@End @Chapter
</xsl:text>
<xsl:if test="not(following-sibling::chapter)">@EndChapters
</xsl:if>
</xsl:template>
<xsl:template match="/book">
<xsl:text>@Book @Begin
</xsl:text>
<xsl:apply-templates select="chapter|exslt:node-set($orphan)"/>
<xsl:text>@End @Book
</xsl:text>
</xsl:template>
</xsl:stylesheet>
@开始
;
@第@Begin和#xa节;
@端部@截面和#xa;
@端部和#xa;
@BeginChapters和#xa;
@第@Begin和#xa章;
@第章结束
;
@尾章
;
@书籍@Begin
;
@结束@Book
;
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="chapter|section" mode="chapter" name="makeChapter">
<xsl:text> @Chapter @Begin
</xsl:text>
<xsl:apply-templates select="self::chapter/node()[1]|
self::section"
mode="section"/>
<xsl:text> @End @Chapter
</xsl:text>
<xsl:apply-templates
select="self::chapter/following-sibling::node()[1]|
self::section/following-sibling::chapter[1] "
mode="chapter"/>
</xsl:template>
<xsl:template match="section" mode="makeSection" name="makeSection">
<xsl:text> @Section @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text> @End @Section
</xsl:text>
<xsl:apply-templates select="following-sibling::node()[1]/self::section"
mode="makeSection"/>
</xsl:template>
<xsl:template match="section" mode="section">
<xsl:text> @BeginSections
</xsl:text>
<xsl:call-template name="makeSection"/>
<xsl:text> @EndSections
</xsl:text>
</xsl:template>
<xsl:template match="book/chapter|book/section">
<xsl:text> @BeginChapters
</xsl:text>
<xsl:call-template name="makeChapter"/>
<xsl:text> @EndChapters
</xsl:text>
</xsl:template>
<xsl:template match="book">
<xsl:text>@Book @Begin
</xsl:text>
<xsl:apply-templates select="node()[1]"/>
<xsl:text>@End @Book
</xsl:text>
</xsl:template>
</xsl:stylesheet>
注意:细粒度遍历,将相邻书籍/章节分组为一章
编辑:按照章节的同级过程更正
通过此输入:
<book>
<section/>
<section/>
<section/>
<chapter/>
<section/>
</book>
编辑:更好地理解命名模板
注意:五条规则:
book
规则“打开”一本书并处理第一个孩子book/section | book/chapter
规则(始终是第一个规则,因为细粒度的横向“打开”book章节,调用makeChapter
<代码>生成章节规则,“打开”一章,如果上下文是章节
则处理第一个孩子,如果上下文是章节
则处理自己,如果上下文是章节
模式下的章节
则处理下一个兄弟姐妹,如果上下文是章节
则处理下一个兄弟姐妹(表示下一章);section
模式下的section
规则(因为逐节点处理,对于相邻的sections
),它将始终匹配第一个节
)“打开”章节调用makeSection
规则;makeSection
规则“打开”一个段处理子段,然后在makeSection
模式下处理下一个同级section
(此规则).不能使用某种形式的“或”,用于计算章节或章节。匹配其中一个章节后,继续匹配一个或多个章节+1:Ah!这看起来很有趣。我会尝试理解一下,看看是否可以扩展。@Frerich Raabe:添加了解释。
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common">
<xsl:output method="html" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="orphan">
<chapter>
<xsl:for-each select="/book/section">
<xsl:copy-of select="." />
</xsl:for-each>
</chapter>
</xsl:variable>
<xsl:template match="section">
<xsl:if test="not(preceding-sibling::section)">@BeginSections
</xsl:if>
<xsl:text>@Section @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text>@End @Section
</xsl:text>
<xsl:if test="not(following-sibling::section)">@EndSections
</xsl:if>
</xsl:template>
<xsl:template match="chapter">
<xsl:if test="not(preceding-sibling::chapter)">@BeginChapters
</xsl:if>
<xsl:text>@Chapter @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text>@End @Chapter
</xsl:text>
<xsl:if test="not(following-sibling::chapter)">@EndChapters
</xsl:if>
</xsl:template>
<xsl:template match="/book">
<xsl:text>@Book @Begin
</xsl:text>
<xsl:apply-templates select="chapter|exslt:node-set($orphan)"/>
<xsl:text>@End @Book
</xsl:text>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="chapter|section" mode="chapter" name="makeChapter">
<xsl:text> @Chapter @Begin
</xsl:text>
<xsl:apply-templates select="self::chapter/node()[1]|
self::section"
mode="section"/>
<xsl:text> @End @Chapter
</xsl:text>
<xsl:apply-templates
select="self::chapter/following-sibling::node()[1]|
self::section/following-sibling::chapter[1] "
mode="chapter"/>
</xsl:template>
<xsl:template match="section" mode="makeSection" name="makeSection">
<xsl:text> @Section @Begin
</xsl:text>
<xsl:apply-templates/>
<xsl:text> @End @Section
</xsl:text>
<xsl:apply-templates select="following-sibling::node()[1]/self::section"
mode="makeSection"/>
</xsl:template>
<xsl:template match="section" mode="section">
<xsl:text> @BeginSections
</xsl:text>
<xsl:call-template name="makeSection"/>
<xsl:text> @EndSections
</xsl:text>
</xsl:template>
<xsl:template match="book/chapter|book/section">
<xsl:text> @BeginChapters
</xsl:text>
<xsl:call-template name="makeChapter"/>
<xsl:text> @EndChapters
</xsl:text>
</xsl:template>
<xsl:template match="book">
<xsl:text>@Book @Begin
</xsl:text>
<xsl:apply-templates select="node()[1]"/>
<xsl:text>@End @Book
</xsl:text>
</xsl:template>
</xsl:stylesheet>
@Book @Begin
@BeginChapters
@Chapter @Begin
@BeginSections
@Section @Begin
@End @Section
@EndSections
@End @Chapter
@Chapter @Begin
@End @Chapter
@EndChapters
@End @Book
<book>
<section/>
<section/>
<section/>
<chapter/>
<section/>
</book>
@Book @Begin
@BeginChapters
@Chapter @Begin
@BeginSections
@Section @Begin
@End @Section
@Section @Begin
@End @Section
@Section @Begin
@End @Section
@EndSections
@End @Chapter
@Chapter @Begin
@End @Chapter
@Chapter @Begin
@BeginSections
@Section @Begin
@End @Section
@EndSections
@End @Chapter
@EndChapters
@End @Book