2016-03-03 91 views
1

使用XPath或XSLT 1.0,我需要找到處理指令<?start?><?end?>之間的每個節點。下面的代碼:查找每個處理指令之間的所有XML節點

//node()[preceding-sibling::processing-instruction()[self::processing-instruction('start')] 
following-sibling::processing-instruction()[ self::processing-instruction('end')]]`, 

的作品,但自然,它只能選擇第一個PI和最後一個PI之間的節點。有沒有辦法只選擇每個開始 - 結束對之間的節點?

<root> 
    abc 

<?start?>def<Highlighted 
    bold="yes"><Highlighted italic="yes">ghi</Highlighted></Highlighted>jkl 
    <?pi?> 
    <table> 
     <Caption>stu</Caption> 
    </table>vw 

<?end?> 
xy<?start?> 
abc <Caption>def</Caption> ghi<?end?> jkl 
</root> 
+0

該問題被標記爲XSLT和XPath。你需要一個純粹的XPath解決方案還是你想用XSLT來解決這個問題?此外,你可以使用XSLT/XPath 2.0(比如' ...''? –

+0

如果不可能使用純XPath解決方案,那麼可以使用XSLT 1.0,但不能使用XSLT 2.0,忘記提及它吧。 –

+0

我編輯了我的答案並添加了一個XSLT 1.0的方法 –

回答

2

下面是一個使用for-each-group group-starting-with/group-ending-with找到並輸出那些對處理指令之間的節點的XSLT 2.0例如:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

<xsl:output indent="yes"/> 

<xsl:template match="root"> 
    <xsl:for-each-group select="node()" group-starting-with="processing-instruction('start')"> 
     <xsl:if test="self::processing-instruction('start')"> 
      <group> 
       <xsl:for-each-group select="current-group() except ." group-ending-with="processing-instruction('end')"> 
        <xsl:sequence select="current-group()[position() ne last()]"/> 
       </xsl:for-each-group> 
      </group> 
     </xsl:if> 
    </xsl:for-each-group> 
</xsl:template> 

</xsl:stylesheet> 

結果爲您的樣品是

<group>def<Highlighted bold="yes"> 
     <Highlighted italic="yes">ghi</Highlighted> 
    </Highlighted>jkl 
    <?pi?> 
    <table> 
     <Caption>stu</Caption> 
    </table>vw 

    </group> 
<group> 
    abc <Caption>def</Caption> ghi</group> 

使用XSLT 1.0可以計算以下節點的交集:start pi和end pi:

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

    <xsl:output indent="yes"/> 

    <xsl:key name="start" match="root/node()[not(self::processing-instruction('start'))]" use="generate-id(preceding-sibling::processing-instruction('start')[1])"/> 
    <xsl:key name="end" match="root/node()[not(self::processing-instruction('end'))]" use="generate-id(following-sibling::processing-instruction('end')[1])"/> 

    <xsl:template match="root"> 
     <xsl:apply-templates select="processing-instruction('start')"/> 
    </xsl:template> 

    <xsl:template match="processing-instruction('start')"> 
     <xsl:variable name="end" select="following-sibling::processing-instruction('end')[1]"/> 
     <xsl:variable name="following-start" select="key('start', generate-id())"/> 
     <xsl:variable name="preceding-end" select="key('end', generate-id($end))"/> 
     <xsl:variable name="intersect" select="$following-start[count(. | $preceding-end) = count($preceding-end)]"/> 
     <group> 
      <xsl:copy-of select="$intersect"/> 
     </group> 
    </xsl:template> 
</xsl:stylesheet> 
+0

謝謝,這很好,但是我現在需要在輸出的「開始 - 結束」交叉點外還有節點,這意味着在輸出:a)節點在開始交點 - 結束PI將位於組元素中b)交點外的任何節點都將被打印。請注意,輸入文檔可能沒有開始處理指令對。 –

+0

@ L.Vareka,考慮以清晰描述所需輸出作爲代碼示例來提出一個新問題。 –

+0

好的。新的問題是可用的:http://stackoverflow.com/questions/36054922/grouping-xml-nodes-between-each-two-processing-instructions-using-xslt-1-0 –

相關問題