2014-03-12 40 views
0

我有一個複雜的XML,這裏給出了一個簡化版本。 我試圖實現的是從XML中僅從給定節點集合 獲取數據(文本或屬性值)。許多示例僅適用於XPATH。但是我的XML結構很複雜,我想使用遞歸方法掃描節點而不是硬編碼XPATH。如何從XML中選擇多個節點以及該節點的文本或屬性值

INPUT:

<Root> 
    <Book> 
    <Content > 
    <Chapter id="1" startpage="1" endpage="20"> 
     <Topic id="1"> 
     <Title>Title1</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
     <Topic id="1.1"> 
     <Title>Title1.1</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
     <Topic id="1.2"> 
     <Title>Title1.2</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
    </Chapter> 
    <Chapter id="2" startpage="21" endpage="90"> 
     <Topic id="2"> 
     <Title>Title2</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
     <Topic id="2.1"> 
     <Title>Title2.1</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
     <Topic id="2.1.2"> 
     <Title>Title2.1.2</Title> 
     <Content>Paragraphs</Content> 
     </Topic> 
    </Chapter> 
    <Index> 
    Some more nodes here 
    </Index> 
      </Content> 
    </Book> 
</Root> 

期望的輸出:

<Root> 
<Book> 
<Content> 
    <Chapter id="1" startpage="1" endpage="20"> 

    <Title>Title1</Title> 

    <Title>Title1.1</Title> 

    <Title>Title1.2</Title> 

    </Chapter> 
<Chapter id="2" startpage="21" endpage="90"> 

    <Title>Title2</Title> 

    <Title>Title2.1</Title> 

    <Title>Title2.1.2</Title> 

</Chapter> 

</Book> 
</Root> 

CURRENT XSL:

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

    <ns:WhiteList> 
     <name>Root</name> 
     <name>Book</name> 
     <name>Chapter</name> 
     <name>Title</name> 
    </ns:WhiteList> 

    <xsl:variable name="whistList" select="document('')/*/ns:WhiteList" /> 

    <xsl:template match="node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="@*"> 
     <xsl:if test="attribute::*[name()=$whistList/*]"> 
     <xsl:copy/> 

     </xsl:if> 
    </xsl:template> 

    <xsl:template match="*"> 
     <xsl:if test="descendant-or-self::*[name()=$whistList/*]"> 
     <xsl:copy> 
      <xsl:value-of select="node()" /> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 

     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

回答

0

如果只有決定因素是節點的名稱(不管路徑節點的),你可以嘗試:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common"> 

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:variable name="whiteList"> 
    <name>Root</name> 
    <name>Book</name> 
    <name>Chapter</name> 
    <name>Title</name> 
    <name>id</name> 
</xsl:variable> 
<xsl:variable name="whiteListSet" select="exsl:node-set($whiteList)/name" /> 

<xsl:template match="*"> 
    <xsl:choose> 
     <xsl:when test="name()=$whiteListSet"> 
      <xsl:copy> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:copy> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:if test="name()=$whiteListSet and name(parent::*)=$whiteListSet"> 
     <xsl:copy/> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="text()"> 
    <xsl:if test="name(parent::*)=$whiteListSet"> 
     <xsl:copy/> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

當上述應用到你的榜樣輸入時,結果是:

<?xml version="1.0" encoding="UTF-8"?> 
<Root> 
    <Book> 
     <Chapter id="1"> 
     <Title>Title1</Title> 
     <Title>Title1.1</Title> 
     <Title>Title1.2</Title> 
     </Chapter> 
     <Chapter id="2"> 
     <Title>Title2</Title> 
     <Title>Title2.1</Title> 
     <Title>Title2.1.2</Title> 
     </Chapter> 
    </Book> 
</Root> 
+0

謝謝邁克爾。您的回答是準確的,並按預期工作。 – user3391883

1

我已經添加了跟隨着G貴樣式表:

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

現在的輸出是

<Root> 
    <Book> 
     <Content> 
     <Chapter> 
      <id>1</id> 
      <startpage>1</startpage> 
      <endpage>20</endpage> 
      <Title>Title1</Title> 
      <Title>Title1.1</Title> 
      <Title>Title1.2</Title> 
     </Chapter> 
     <Chapter> 
      <id>2</id> 
      <startpage>21</startpage> 
      <endpage>90</endpage> 
      <Title>Title2</Title> 
      <Title>Title2.1</Title> 
      <Title>Title2.1.2</Title> 
     </Chapter> 
     </Content> 
    </Book> 
</Root> 
+0

嗨,謝謝你的回覆。正如我所提到的,這只是我的XML的一個簡單版本。在我的實際XML中使用XPATH將非常棘手,因爲它非常龐大並且嵌套很多。所以我正在尋找更好的替代方案。一種可能的選擇是遞歸。 – user3391883

+0

@ user3391883如果您沒有顯示_actual_ XML作爲輸入,那麼在此處詢問將毫無用處。無論如何,你只是浪費了人們的時間,因爲他們的解決方案無法工作。請張貼實際的輸入XML,以及如何將其轉換爲您想要的輸出的準確說明。我相信你不需要爲此遞歸,並且它不會是一個可行的解決方案。 –

+0

我的原始XML是37947行,我相信堆棧溢出不會允許將這個大的XML添加爲代碼。 – user3391883

0

看起來像這樣的工作。但是,它仍然顯示我不想要的節點。我相信那是因爲節點有一個屬性。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="some:ns"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <ns:WhiteList> 
      <elename>Chapter</elename> 
      <elename>Title</elename> 
    </ns:WhiteList> 
    <xsl:variable name="whistList" select="document('')/*/ns:WhiteList" /> 

    <xsl:template match="node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="@*"> 
     <xsl:copy> 
      <xsl:call-template name="flatattr"/> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="@*" name="flatattr"> 
     <xsl:element name="{local-name()}"> 
      <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 
    <xsl:template match="*"> 
     <xsl:if test="descendant-or-self::*[name()=$whistList/*]"> 
      <xsl:copy> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="Expression[ancestor::Expression]"> 
     <xsl:apply-templates /> 
    </xsl:template> 
    <xsl:template match="SimpleExpression"> 
     <xsl:text>(</xsl:text> 
     <xsl:apply-templates /> 
     <xsl:text>)</xsl:text> 
    </xsl:template> 
    <xsl:template match="ValueExpression|Operator"> 
     <xsl:text>(</xsl:text> 
     <xsl:value-of select="." /> 
     <xsl:text>)</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 
+0

,你不想要什麼? –

+0

它仍然顯示包含子節點或空的節點。 e..g在原始的xml書籍和內容節點中。有沒有辦法消除它們。我假設保留結構XSL保留他們 – user3391883

+0

我已編輯我的答案,請看看。 –

相關問題