2017-06-05 56 views
1

我从基础ePub输出中找到一个XHTML文档,我试图将其转换为结构化XML文档。它的格式不应该是一般的太疯狂了,看起来像下面这样:使用XSLT 1.0将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中的东西应该包含在它自己的文档的末尾。同样,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的,等元素,所以它是只有一个节点不计。它需要足够通用,不必关心标题标签之间的内容。

我熟悉Muenchian分组,但这对我来说有点复杂。我已经尝试使用键这样的:

<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 *元素的脚本元素。如何添加附加图层的简单说明就足够了。

有没有人在这里有一些建议?

回答

1

下面的样式表(大部分来自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> 
+0

完美!当我搜索帖子时,我没有遇到过这种情况,而且似乎它占了我所需要的大部分。感谢您调整它并保存我的理智。我也不知道我可以'添加'到键。我只会定义一次。所以我也学到了一些东西! – Greg

+0

不客气! :) –

1

这将这样的伎俩:

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

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

    <xsl:template match="*[starts-with(local-name(), 'h')]"> 
    <xsl:variable name="lvl" select="number(substring-after(local-name(), 'h'))"/> 
    <Topic> 
     <Title> 
     <xsl:value-of select="text()"/> 
     </Title> 
     <xsl:apply-templates select="//following-sibling::*[not(starts-with(local-name(), 'h')) 
          and preceding-sibling::*[starts-with(local-name(), 'h')][1] = current()]"/> 
     <xsl:apply-templates select="//following-sibling::*[local-name() = concat('h', $lvl + 1) 
          and preceding-sibling::*[local-name() = concat('h', $lvl)][1] = current()]"/> 
    </Topic> 
    </xsl:template> 

    <xsl:template match="*"> 
    <Paragraph> 
     <xsl:value-of select="text()"/> 
    </Paragraph> 
    </xsl:template> 
</xsl:stylesheet> 
+0

我还测试了这款之一,似乎伎俩,但没有钥匙。它也更加浓缩一点。不是很简单地知道它可以做到,但仍然是一个非常有效的答案! – Greg

+0

@Greg,很酷谢谢 –