2012-01-22 43 views
4

什麼是xpath表達式來選擇文檔的所有節點?如何使用單個DOMXpath表達式選擇DOMDocument的所有節點?

鑑於此示例XML:

<div class="header"/> 

我包含三個節點:<div>(元素),class=(屬性)和"header"(文本)。

$doc = new DOMDocument; 
$doc->loadXml('<div class="header"/>'); 
$xpath = new DOMXPath($doc); 

我試圖與//node()

$xpath->query('//node()'); 

其中僅返回所有元素節點(I假設由於//)。有沒有辦法在屬性值中添加其他節點,如屬性和文本節點?


附加例如:

我可以通過使用DOMDocument API獲得的每個節點,例如獲得屬性值的文本節點:

$doc = new DOMDocument; 
$doc->loadXml('<div class="header"/>'); 
$class = $doc->documentElement->getAttributeNode('class'); 
echo $class->childNodes->item(0)->nodeName; 

其中給出:

#text 

如何獲取所有節點的超一個XPath表達式,特別是包括示範性的class屬性的子節點文本-節點?

回答

3

使用

//node() | //@* | //namespace::* 

此選擇和任何屬性節點和任何命名空間節點(類型文檔節點/,元素節點,文本節點,處理指令節點和註釋節點的)任何節點 - 即是所有節點,因爲沒有其他類型的節點。

如何訪問獲取的包含選定節點的XmlNodeList取決於您正在使用的特定XPath引擎的API - 讀取並使用您的文檔。基於

XSLT-例如

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

<xsl:template match="/"> 

    <xsl:for-each select= 
    "//node() | //@* | //namespace::*"> 

    Type: <xsl:text/> 

    <xsl:choose> 
    <xsl:when test="not(..)"> 
    <xsl:text>document node </xsl:text> 
    </xsl:when> 
    <xsl:when test="self::*"> 
    <xsl:text>element </xsl:text> 
    </xsl:when> 
    <xsl:when test="self::text()"> 
    <xsl:text>text-node </xsl:text> 
    </xsl:when> 
    <xsl:when test="self::comment()"> 
    <xsl:text>comment-node </xsl:text> 
    </xsl:when> 
    <xsl:when test="self::processing-instruction()"> 
    <xsl:text>PI-node </xsl:text> 
    </xsl:when> 
    <xsl:when test="count(.|../@*) = count(../@*)"> 
    <xsl:text>attribute-node </xsl:text> 
    </xsl:when> 
    <xsl:when test= 
    "count(.|../namespace::*) = count(../namespace::*)"> 
    <xsl:text>namespace-node </xsl:text> 
    </xsl:when> 
    </xsl:choose> 

    <xsl:text>Name: "</xsl:text> 
    <xsl:value-of select="name()"/>" <xsl:text/> 

    <xsl:text>Value: </xsl:text> 
    <xsl:value-of select="."/> 

    </xsl:for-each> 

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

當該XSLT轉換是在任何XML文檔施加它選擇使用上述XPath表達式的所有節點(變換有意排除任何空白僅文本節點)和輸出(按文件順序)所選節點的類型,名稱和字符串值。

例如,當這個XML文檔施加:

<networkOfBridges xmlns:x="x"> 
    <bridge id="1" otherside="A" /> 
    <!-- A Comment --> 
    <bridge id="2" oneside="A"/> 
    <?PI Processing Instruction ?> 
    <bridge id="3" oneside="A" otherside="A" /> 
</networkOfBridges> 

結果是

Type: element Name: "networkOfBridges" Value: 

    Type: namespace-node Name: "xml" Value: http://www.w3.org/XML/1998/namespace 

    Type: namespace-node Name: "x" Value: x 

    Type: element Name: "bridge" Value: 

    Type: namespace-node Name: "xml" Value: http://www.w3.org/XML/1998/namespace 

    Type: namespace-node Name: "x" Value: x 

    Type: attribute-node Name: "id" Value: 1 

    Type: attribute-node Name: "otherside" Value: A 

    Type: comment-node Name: "" Value: A Comment 

    Type: element Name: "bridge" Value: 

    Type: namespace-node Name: "xml" Value: http://www.w3.org/XML/1998/namespace 

    Type: namespace-node Name: "x" Value: x 

    Type: attribute-node Name: "id" Value: 2 

    Type: attribute-node Name: "oneside" Value: A 

    Type: PI-node Name: "PI" Value: Processing Instruction 

    Type: element Name: "bridge" Value: 

    Type: namespace-node Name: "xml" Value: http://www.w3.org/XML/1998/namespace 

    Type: namespace-node Name: "x" Value: x 

    Type: attribute-node Name: "id" Value: 3 

    Type: attribute-node Name: "oneside" Value: A 

    Type: attribute-node Name: "otherside" Value: A 
1

你試過類似//*|//@*|//text()的東西嗎?

+0

我現在用'做// * | // @ *'將選擇所有元素和屬性,但不會選擇屬性值。我遺漏了// text(),因爲它在示例XML中沒有什麼不同。所以你的建議可能是朝着正確方向邁出的一步。 – hakre

+0

我不認爲你可以自己獲得屬性值。 – greut

3

您的示例實際上只包含兩個節點:元素(div)和屬性(class="header")。所以,「標題」是屬性的值,而不是單獨的節點。

文本節點確實存在,但它們用於元素之間的文本。例如,在<title>Alice in wonderland</title>中,有兩個節點:元素(title)和文本節點(Alice in wonderland)。

因此,在這種情況下你可以做的最好的是//*|//@*

編輯,在你的問題更新後。

文本節點的存在是由於php特定的實現,它不是W3C standard的一部分。無論實現如何,XPath只考慮2個節點。

說了這麼多,你可以使用一些XPath functions來得到你想要的。函數name()返回節點的名稱,函數string()返回字符串值。也許你可以使用這些來獲取字符串(而不是節點)。

-1
foreach ($xpath->query('//*[count(*) = 0]') as $node) { 
    $path = array(); 
    $val = $node->nodeValue; 
    do { 
     $path[] = $node->nodeName; 
    } 
    while ($node = $node->parentNode); 
    $result[implode('/', array_reverse($path))] = $val; 
} 
+0

這隻會選擇只是一個子集的元素。您可能也對http://php.net/manual/en/domnode.getnodepath.php – hakre

+0

感興趣,因爲他們沒有解釋他們如何解決問題,所以不提供代碼解答。請更新您的答案,以解釋這個問題已經具有的其他已接受和已獲得解答的答案是如何改進的。請複習[我如何寫出一個好答案](https://stackoverflow.com/help/how-to-answer)。 – FluffyKitten

相關問題