繁体   English   中英

如何使用单个DOMXpath表达式选择DOMDocument的所有节点?

[英]How to select all nodes of a DOMDocument with a single DOMXpath expression?

选择文档的所有节点的xpath表达式是什么?

给出这个例子XML:

<div class="header"/>

我包含三个节点: <div> (元素), class= (属性)和"header" (文本)。

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

我尝试使用//node()

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

它只返回所有元素节点(我假设因为// )。 有没有办法在属性值中添加属性和文本节点等其他节点?


附加示例:

我可以使用DOMDocument API获取每个节点,例如获取属性值的文本节点:

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

这使:

#text

如何获取具有一个xpath表达式的所有节点的超集,尤其是包括该示例性class属性 - 节点子文本节点?

您的示例实际上只包含两个节点:元素( div )和属性( class="header" )。 因此,“header”是属性的值,而不是单独的节点。

文本节点确实存在,但它们用于元素之间的文本。 例如,在<title>Alice in wonderland</title> ,有两个节点:元素( title )和文本节点( Alice in wonderland )。

因此,在这种情况下你能做的最好的是//*|//@*

在您对问题进行更新后编辑。

文本节点的存在是由于特定于php的实现,它不是W3C标准的一部分。 无论实现如何,XPath都只考虑2个节点。

话虽如此,您可以使用一些XPath函数来获得您想要的。 函数name()返回节点的名称,函数string()返回字符串值。 也许您可以使用这些来获取字符串(而不是节点)。

用途

//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

你尝试过类似//*|//@*|//text()吗?

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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM