2013-11-14 37 views
2

我有以下XSLT,它爲填充的XML文件中的每個元素創建XPATH。從XML文檔生成XPATH到屬性級別

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text" indent="no"/> 
<xsl:template match="*[not(*)]"> 
    <xsl:for-each select="ancestor-or-self::*"> 
     <xsl:value-of select="concat('/', name())"/> 
     <xsl:if test="count(preceding-sibling::*[name() = name(current())]) != 0"> 
      <xsl:value-of select="concat('[', count(preceding-sibling::*[name() = name(current())]) + 1, ']')"/> 
     </xsl:if> 
    </xsl:for-each> 
    <xsl:text>&#xA;</xsl:text> 
    <xsl:apply-templates select="*"/> 
</xsl:template> 
<xsl:template match="*"> 
    <xsl:apply-templates select="*"/> 
</xsl:template> 
</xsl:stylesheet> 

我想擴大這個範圍,以便產生一個獨特的行到'attribue'級別。目前,即使具有多個屬性,也會爲給定元素生成一條XPATH語句。如果一個元素有3個屬性,我想爲每個生成的3個XPATH行。任何想法讚賞! :)謝謝

修訂

伊恩嗨,

真的很感謝你的幫助。

我需要一個增強功能,我覺得很棘手?

其中元素具有xsi:type屬性(即是另一種類型的擴展名),我需要在元素名稱在XPath,而不是作爲一個屬性本身(被認爲是一種特殊的/保留XSD屬性)

eg對於

<a> 
    <b xsi:type="c" attribute1="at1"/> 
</a> 

我需要:

/a/b[xsi:type="c"]/@attribute1 

而不是

/a/b/@type 

它是目前生產?這可能嗎?

謝謝!

UPDATE

非常感謝!請最後一個請求。 :)你可以調整它來添加元素或屬性VALUE從XML中,通過逗號分隔從XPATH部分分離.....所以是[XPATH],[VALUE]

+0

嗨伊恩, 真的很感謝你的幫助。 我需要一個增強,我覺得很棘手? 如果一個元素具有xsi:type屬性(即,是另一種類型的擴展),我需要在XPATH中的*元素名稱*中考慮這一點,而不是將其作爲屬性本身(因爲它是一個特殊/保留XSD屬性) 例如對於 我需要: /A/B [的xsi:type = 「C」]/@ ATTRIBUTE1 而不是 /a/b/@類型 它目前正在生產?這可能嗎? 謝謝! – user2992225

回答

0

我會拉出路徑生成代碼到另一個模板,然後調入,從模板元素和屬性:

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

    <xsl:template mode="path" match="*"> 
    <xsl:for-each select="ancestor-or-self::*"> 
     <xsl:value-of select="concat('/', name())" /> 
     <xsl:if test="count(preceding-sibling::*[name() = name(current())]) != 0"> 
     <xsl:value-of select="concat('[', 
      count(preceding-sibling::*[name() = name(current())]) + 1, ']')" /> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:if test="not(*)"> 
     <!-- this element has no children, print its path --> 
     <xsl:apply-templates mode="path" select="." /> 
     <xsl:text>&#xa;</xsl:text> 
    </xsl:if> 
    <xsl:apply-templates select="@*|*" /> 
    </xsl:template> 

    <xsl:template match="@*"> 
    <!-- for an attribute, print the path to its containing element ... --> 
    <xsl:apply-templates mode="path" select=".." /> 
    <!-- ... followed by "/@attributename" --> 
    <xsl:value-of select="concat('/@', name(), '&#xa;')" /> 
    </xsl:template> 
</xsl:stylesheet> 

這是,雖然屬性節點不被認爲是他們的主元素節點的孩子XPath數據模型的方便古怪,元素被認爲是其屬性節點的父項。


更新:處理xsi:type要求,你就應該能夠到邏輯添加到您當前的兄弟姐妹計數代碼,區別對待類型元素。並且要在適當的位置添加值,您需要合適的value-of

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <xsl:output method="text" indent="no" /> 

    <xsl:template mode="path" match="*"> 
    <xsl:for-each select="ancestor-or-self::*"> 
     <xsl:value-of select="concat('/', name())" /> 
     <!-- for typed elements, include the type in the path --> 
     <xsl:if test="@xsi:type"> 
     <xsl:text>[@xsi:type = '</xsl:text> 
     <xsl:value-of select="@xsi:type" /> 
     <xsl:text>']</xsl:text> 
     </xsl:if> 
     <xsl:if test="count(preceding-sibling::*[name() = name(current()) and 
      @xsi:type = current()/@xsi:type]) != 0"> 
     <xsl:value-of select="concat('[', 
      count(preceding-sibling::*[name() = name(current()) and 
      @xsi:type = current()/@xsi:type]) + 1, ']')" /> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:if test="not(*)"> 
     <!-- this element has no children, print its path --> 
     <xsl:apply-templates mode="path" select="." /> 
     <xsl:text>,</xsl:text> 
     <xsl:value-of select="."/> 
     <xsl:text>&#xa;</xsl:text> 
    </xsl:if> 
    <xsl:apply-templates select="@*|*" /> 
    </xsl:template> 

    <xsl:template match="@*"> 
    <!-- for an attribute, print the path to its containing element ... --> 
    <xsl:apply-templates mode="path" select=".." /> 
    <!-- ... followed by "/@attributename" --> 
    <xsl:value-of select="concat('/@', name(), ',', ., '&#xa;')" /> 
    </xsl:template> 
</xsl:stylesheet> 

由於空節點集的字符串值是空字符串,在元素做@xsi:type = current()/@xsi:type沒有一個xsi:type安全,會產生正確的結果。

你也可能要添加

<xsl:template match="@xsi:type" /> 

,如果你不希望生成路徑的類型的屬性。

這是這裏值得注意的是該類型的邏輯和計數是正交的 - 給

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <a xsi:type="xs:string">aaa</a> 
    <a xsi:type="xs:integer">1</a> 
    <a xsi:type="xs:string">bbb</a> 
    <a xsi:type="xs:integer">2</a> 
</root> 

你會得到的

/root/a[@xsi:type = 'xs:string'],aaa 
/root/a[@xsi:type = 'xs:integer'],1 
/root/a[@xsi:type = 'xs:string'][2],bbb 
/root/a[@xsi:type = 'xs:integer'][2],2 

路徑,每個類型的計數(這是正確的,的XPath將假設正確的命名空間綁定選擇正確的事物)。

+0

非常感謝堆伊恩 - 傳奇! – user2992225

+0

Ive更新了這個問題,不確定你是否可以幫助進行'小調'Ian? Ta – user2992225

+0

@ user2992225這個怎麼樣?順便說一句,將來可能值得考慮將這樣的重大變化帶入一個新的問題,而不是編輯一個已經有了正確答案的已有問題。 –