使用XPath在PHP中提取XML

dr_*_*_rk 1 php xml xpath

我有以下XML:

<root>
   <level name="level1">
       <!-- More children <level> --> 
   </level>

   <level name="level2"> 
       <!-- Some more children <level> --> 
   </level> 
</root>
Run Code Online (Sandbox Code Playgroud)

我怎样才能<level>直接提取一个,<root>以便我可以运行一个XPath查询,例如$xml->xpath('//some-query')相对于所提取的<level>

Vol*_*erK 7

DOMXPath::query的第二个参数是上下文节点。只需传递您之前“找到”的 DOMNode 实例,您的查询就会“相对”运行到该节点。例如

<?php
$doc = new DOMDocument;
$doc->loadxml( data() );

$xpath = new DOMXPath($doc);
$nset = $xpath->query('/root/level[@name="level1"]');
if ( $nset->length < 1 ) {
    die('....no such element');
}
else {
    $elLevel = $nset->item(0);

    foreach( $xpath->query('c', $elLevel) as $elC) {
        echo $elC->nodeValue, "\r\n";
    }
}


function data() {
    return <<< eox
<root>
    <level name="level1">
        <c>C1</c>
        <a>A</a>
        <c>C2</c>
        <b>B</b>
        <c>C3</c>
    </level>
    <level name="level2"> 
        <!-- Some more children <level> --> 
    </level> 
</root>
eox;
}
Run Code Online (Sandbox Code Playgroud)

但是除非您必须执行多个单独的(可能是复杂的)后续查询,否则这很可能没有必要

<?php
$doc = new DOMDocument;
$doc->loadxml( data() );

$xpath = new DOMXPath($doc);
foreach( $xpath->query('/root/level[@name="level1"]/c') as $c ) {
    echo $c->nodeValue, "\r\n"; 
}


function data() {
    return <<< eox
<root>
    <level name="level1">
        <c>C1</c>
        <a>A</a>
        <c>C2</c>
        <b>B</b>
        <c>C3</c>
    </level>
    <level name="level2"> 
        <c>Ahh</c>
        <a>ouch</a>
        <c>no</c>
        <b>wrxl</b>
    </level> 
</root>
eox;
}
Run Code Online (Sandbox Code Playgroud)

仅使用一个查询即可获得相同的输出。


ThW*_*ThW 5

DOMXpath::evaluate() 允许您从DOM中获取节点列表和标量值。

因此,您可以使用Xpath表达式直接获取值:

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);

var_dump(
  $xpath->evaluate('string(/root/level[@name="level2"]/@name)')
);
Run Code Online (Sandbox Code Playgroud)

输出:

string(6) "level2"
Run Code Online (Sandbox Code Playgroud)

Xpath表达式

中的所有level元素节点root
/root/level

具有特定的名称属性:
/root/level[@name="level2"]

您要获取的值(name用于验证的属性):
/root/level[@name="level2"]/@name

强制转换为字符串,如果找到节点,则结果将为空字符串:

string(/root/level[@name="level2"]/@name)

遍历节点,将它们用作上下文

如果需要为该节点执行多个表达式,则最好单独获取并使用foreach()。的第二个参数DOMXpath::evaluate()是上下文节点。

foreach ($xpath->evaluate('/root/level[@name="level2"]') as $level) {
  var_dump(
    $xpath->evaluate('string(@name)', $level)
  );
}
Run Code Online (Sandbox Code Playgroud)

节点列表长度

如果需要处理未找到任何节点,则可以检查该DOMNodeList::$length属性。

$levels = $xpath->evaluate('/root/level[@name="level2"]');
if ($levels->length > 0) {
  $level = $levels->item(0);
  var_dump(
    $xpath->evaluate('string(@name)', $level)
  );
} else {
  // no level found
}
Run Code Online (Sandbox Code Playgroud)

count()表达式

您也可以使用count()表达式验证此处是否包含元素。

var_dump(
  $xpath->evaluate('count(/root/level[@name="level2"])')
);
Run Code Online (Sandbox Code Playgroud)

输出:

float(1)
Run Code Online (Sandbox Code Playgroud)

布尔结果

可以在Xpath中将该条件作为条件并返回布尔值。

var_dump(
  $xpath->evaluate('count(/root/level[@name="level2"]) > 0')
);
Run Code Online (Sandbox Code Playgroud)

输出:

bool(true)
Run Code Online (Sandbox Code Playgroud)