如何使XSLT模板处理缺少的父元素?

如何使XSLT模板处理缺少的父元素?,xslt,Xslt,我想为这个糟糕的标题道歉——我真的不知道如何更好地表达它。我目前正在编写XSLT1.0脚本(使用),该脚本将简单的XML格式转换为适合PDF生成器使用的文本表示形式 在我的XML格式中,只有三个元素:、和。然而,由于DTD的一些讨厌的特性,我很难编写一个合适的XSLT脚本来转换文档。以下是描述其关系的DTD: <!ELEMENT book ((chapter|section)*)> <!ELEMENT chapter (section*)> <!ELEMENT se

我想为这个糟糕的标题道歉——我真的不知道如何更好地表达它。我目前正在编写XSLT1.0脚本(使用),该脚本将简单的XML格式转换为适合PDF生成器使用的文本表示形式

在我的XML格式中,只有三个元素:
。然而,由于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&#xa;</xsl:if>
  <xsl:text>@Section @Begin&#xa;</xsl:text>
  <xsl:apply-templates/>
  <xsl:text>@End @Section&#xa;</xsl:text>
  <xsl:if test="not(following-sibling::section)">@EndSections&#xa;</xsl:if>
</xsl:template>

<xsl:template match="chapter">
  <xsl:if test="not(preceding-sibling::chapter)">@BeginChapters&#xa;</xsl:if>
  <xsl:text>@Chapter @Begin&#xa;</xsl:text>
  <xsl:apply-templates/>
  <xsl:text>@End @Chapter&#xa;</xsl:text>
  <xsl:if test="not(following-sibling::chapter)">@EndChapters&#xa;</xsl:if>
</xsl:template>

<xsl:template match="/book">
  <xsl:text>@Book @Begin&#xa;</xsl:text>
  <xsl:apply-templates select="chapter|exslt:node-set($orphan)"/>
  <xsl:text>@End @Book&#xa;</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&#xa;</xsl:text>
        <xsl:apply-templates select="self::chapter/node()[1]|
                                     self::section"
                             mode="section"/>
        <xsl:text>  @End @Chapter&#xa;</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&#xa;</xsl:text>
        <xsl:apply-templates/>
        <xsl:text>    @End @Section&#xa;</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&#xa;</xsl:text>
        <xsl:call-template name="makeSection"/>
        <xsl:text>    @EndSections&#xa;</xsl:text>
    </xsl:template>
    <xsl:template match="book/chapter|book/section">
        <xsl:text>  @BeginChapters&#xa;</xsl:text>
        <xsl:call-template name="makeChapter"/>
        <xsl:text>  @EndChapters&#xa;</xsl:text>
    </xsl:template>
    <xsl:template match="book">
        <xsl:text>@Book @Begin&#xa;</xsl:text>
        <xsl:apply-templates select="node()[1]"/>
        <xsl:text>@End @Book&#xa;</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&#xa;</xsl:if>
  <xsl:text>@Section @Begin&#xa;</xsl:text>
  <xsl:apply-templates/>
  <xsl:text>@End @Section&#xa;</xsl:text>
  <xsl:if test="not(following-sibling::section)">@EndSections&#xa;</xsl:if>
</xsl:template>

<xsl:template match="chapter">
  <xsl:if test="not(preceding-sibling::chapter)">@BeginChapters&#xa;</xsl:if>
  <xsl:text>@Chapter @Begin&#xa;</xsl:text>
  <xsl:apply-templates/>
  <xsl:text>@End @Chapter&#xa;</xsl:text>
  <xsl:if test="not(following-sibling::chapter)">@EndChapters&#xa;</xsl:if>
</xsl:template>

<xsl:template match="/book">
  <xsl:text>@Book @Begin&#xa;</xsl:text>
  <xsl:apply-templates select="chapter|exslt:node-set($orphan)"/>
  <xsl:text>@End @Book&#xa;</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&#xa;</xsl:text>
        <xsl:apply-templates select="self::chapter/node()[1]|
                                     self::section"
                             mode="section"/>
        <xsl:text>  @End @Chapter&#xa;</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&#xa;</xsl:text>
        <xsl:apply-templates/>
        <xsl:text>    @End @Section&#xa;</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&#xa;</xsl:text>
        <xsl:call-template name="makeSection"/>
        <xsl:text>    @EndSections&#xa;</xsl:text>
    </xsl:template>
    <xsl:template match="book/chapter|book/section">
        <xsl:text>  @BeginChapters&#xa;</xsl:text>
        <xsl:call-template name="makeChapter"/>
        <xsl:text>  @EndChapters&#xa;</xsl:text>
    </xsl:template>
    <xsl:template match="book">
        <xsl:text>@Book @Begin&#xa;</xsl:text>
        <xsl:apply-templates select="node()[1]"/>
        <xsl:text>@End @Book&#xa;</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