2017-06-05 55 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,很酷謝謝 –