使用XSLT 1.0将XHTML转换为结构化XML [英] XHTML to Structured XML with XSLT 1.0

查看:17
本文介绍了使用XSLT 1.0将XHTML转换为结构化XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个来自基本ePub输出的XHTML文档,我正试图将其转换为结构化XML文档。格式一般不能太疯狂,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<html>
<body>
  <h1>Topic 1</h1>
  <p>1.0.1</p>
  <p>1.0.2</p>

  <h2>Subtopic 1.1</h2>
  <p>1.1.1</p>
  <p>1.1.2</p>

  <h2>Subtopic 1.2</h2>
  <p>1.2.1</p>
  <p>1.2.2</p>

  <h1>Topic 2</h1>
  <p>2.0.1</p>
  <p>2.0.2</p>

  <h2>Subtopic 2.1</h2>
  <p>2.1.1</p>
  <p>2.1.2</p>

  <h2>Subtopic 2.2</h2>
  <p>2.2.1</p>
  <p>2.2.2</p>
</body>
</html>
理想情况下,我希望将其转换为一些结构化代码,基于h1、h2、.标签。第一个h1之后、第二个h1之前的内容应该包含在它自己的容器中,而第二个h1中到文档末尾的内容应该包含在它自己的容器中。同样,H2之间的东西也应该放入一个容器中,从而将其嵌套。输出应如下所示:

<Root>
   <Topic>
      <Title>Topic 1</Title>
      <Paragraph>1.0.1</Paragraph>
      <Paragraph>1.0.2</Paragraph>
      <Topic>
         <Title>Subtopic 1.1</Title>
         <Paragraph>1.1.1</Paragraph>
         <Paragraph>1.1.2</Paragraph>
      </Topic>
      <Topic>
         <Title>Subtopic 1.2</Title>
         <Paragraph>1.2.1</Paragraph>
         <Paragraph>1.2.2</Paragraph>
      </Topic>
   </Topic>
   <Topic>
      <Title>Topic 2</Title>
      <Paragraph>2.0.1</Paragraph>
      <Paragraph>2.0.2</Paragraph>
      <Topic>
         <Title>Subtopic 2.1</Title>
         <Paragraph>2.1.1</Paragraph>
         <Paragraph>2.1.2</Paragraph>
      </Topic>
      <Topic>
         <Title>Subtopic 2.2</Title>
         <Paragraph>2.2.1</Paragraph>
         <Paragraph>2.2.2</Paragraph>
      </Topic>
   </Topic>
</Root>

尽管该示例只包含p标记,但它也可能包含div和其他元素,所以不要指望它只是一个节点。它需要足够通用,以便不关心头标记之间的内容。

我熟悉慕尼黑分组,但这对我来说有点复杂。我尝试过这样使用密钥:

<xsl:key name="kHeaders1" match="*[not(self::h1)]" use="generate-id(preceding-sibling::h1[1])"/>

<xsl:template match="h1">
  <Topic>
    <Title><xsl:apply-templates /></Title>
    <xsl:apply-templates select="key('kHeaders1', generate-id())" />
  </Topic>
</xsl:template>

<xsl:template match="html">
  <Root>
     <xsl:apply-templates select="body/h1" />
  </Root>
</xsl:template>

<xsl:template match="p">
   <Paragraph><xsl:apply-templates /></Paragraph>
</xsl:template>

这对于第一级来说已经足够好了,但是随后尝试重复这个过程,但是使用H2似乎会让我崩溃。因为在h2级别,任何节点的关键字都应该是第一个h1或h2同级节点。它看起来几乎可以组合成一组键,其中id是它之前的最后一个h*是什么,h*元素没有在分组中列出(这样它们就不会递归)。我会想象这样的情况:

<xsl:key name="kHeaders" match="*[not(self::h1 or self::h2)]" use="generate-id(preceding-sibling::*[self::h1 or self::h2][1])"/>
但是,这会从列表中省略h2元素,它们需要出现在前一个h1的分组中。如果我放松对匹配的限制以包括h1/h2元素(并使h1模板也与h2匹配),那么我会得到h2的重新列出h1元素,依此类推(有些出乎意料)。

理想的解决方案是可以轻松扩展到适用于h3、h4等的解决方案。但是,它不需要包括用于处理通用h*元素的脚本元素。有关如何添加附加层的简单说明就足够了。

这里有人有什么建议吗?

推荐答案

下面的样式表(从this answer复制的大多数重要代码)在涉及更多标题时可以正常工作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="next-headings" match="h6"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4 or
                                               self::h5][1])" />

    <xsl:key name="next-headings" match="h5"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4][1])" />
    <xsl:key name="next-headings" match="h4"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3][1])" />
    <xsl:key name="next-headings" match="h3"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2][1])" />

    <xsl:key name="next-headings" match="h2"
          use="generate-id(preceding-sibling::h1[1])" />

    <xsl:key name="immediate-nodes"
          match="node()[not(self::h1 | self::h2 | self::h3 | self::h4 |
                           self::h5 | self::h6)]"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4 or
                                               self::h5 or self::h6][1])" />

    <xsl:template match="/">
        <Root>
            <xsl:apply-templates select="html/body/h1"/>
        </Root>
    </xsl:template>

    <xsl:template match="p">
        <Paragraph>
            <xsl:value-of select="."/>
        </Paragraph>
    </xsl:template>

    <xsl:template match="h1 | h2 | h3 | h4 | h5 | h6">
        <Topic>
            <Title>
                <xsl:value-of select="."/>
            </Title>
            <xsl:apply-templates select="key('immediate-nodes', generate-id())"/>
            <xsl:apply-templates select="key('next-headings', generate-id())"/>
        </Topic>
    </xsl:template>

</xsl:stylesheet>

这篇关于使用XSLT 1.0将XHTML转换为结构化XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆