我有这个示例xml文件:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
<appConfig authenticate="true"></appConfig>
<device>J0A0AM049303</device><!--100001-->
<device>H0A0AG014628</device><!--100002-->
<device>N0A097016646</device><!--100003-->
</rss>
我正在使用以下代码搜索节点值:
<?PHP
$doc = new DOMDocument;
$doc->load('authentication.xml');
$xpath = new DOMXPath($doc);
$searchTerm = "11C1AJ013635";
foreach ($xpath->query("//device[contains(text(), '$searchTerm')]/following::comment()") as $comment)
{
echo "Line number: ".$comment->getLineNo(). '<br/>'.
" Device number: ".$searchTerm.'<br/>'.
" Comented number: ". $comment->textContent."<hr>";
break;
}
?>
现在,我只想在将行号作为搜索词时搜索节点值。 请帮我解决这个问题。上面的代码工作正常,所以你可以复制并根据我的新请求编辑它。 尊重你的帮助。 谢谢!
答案 0 :(得分:2)
XML文档中的行号没有太大意义,因为整个文档可以放在一行而不会改变其中编码的实际数据。
因此,行号或多或少提供了信息。更糟糕的是:它可能不明确,同一行号上可能有多个 device 元素。
您已经针对您的问题解决了一个最大的缺点:您无法在xpath中搜索行号。
因此,寻找一个没有所有这些负面属性的不同数字也许值得。
这里可能更有意义的是找到的<device>
元素的数量或位置。它可以直接在XPath表达式中查询,“//device[1]
”是文档中的第一个设备元素。
此外,首先检索您正在寻找的设备元素,然后检查您感兴趣的各种属性,您的代码可能会受益。
接下来,您需要正确引用所查找的搜索词,因为您将字符串直接注入xpath表达式(我的示例代码使用xpath_string()
function)。
我在变量$buffer
中使用XML以使代码更具可移植性:
$buffer = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
<appConfig authenticate="true"></appConfig>
<device>J0A0AM049303</device><!--100001-->
<device>H0A0AG014628</device><!--100002-->
<device>N0A097016646</device><!--100003-->
<device>11C1AJ013635</device><!--100004-->
</rss>
XML;
然后在设置主要协作者 DOMDocument 和 DOMXPath 时使用:
$doc = new DOMDocument;
$doc->loadXML($buffer);
$xpath = new DOMXPath($doc);
下一部分是根据搜索词查询设备元素。您会发现代码存在两个主要差异:首先,现在引用搜索词来缓解XPath注入,其次是XPath表达式正在寻找设备元素,而不是那些注释之后的注释第三,我不测试文本节点(text()
),但搜索设备的文本内容:
$searchTerm = "3";
$expression = sprintf("//device[contains(., %s)]", xpath_string($searchTerm));
$devices = $xpath->query($expression);
printf("Search term: %s; found %d device(s):\n", $searchTerm, $devices->length);
XPath表达式$expression
是:
//device[contains(., '3')]
使用这个广泛的搜索词“3”和示例XML,它会创建两个结果,也会显示摘要输出:
Search term: 3; found 2 device(s):
由于搜索到的所有设备现在都位于$devices
内,因此可以通过迭代它们并获取它们来获取您正在寻找的所有属性(甚至更多这些属性)。我有以下属性列表:
foreach ($devices as $index => $device) {
# ... obtain and process the infos from $device ...
}
可以通过直接在设备元素$device
上操作或通过将XPath表达式作为上下文节点执行来获取这些信息(从相对于元素的角度来看)。例如,获取尚未丢失的注释节点:
$comment = $xpath->query('following::comment()', $device);
xpath表达式“following::comment()
”我从您的XPath中获取并且它在此处锚定到$device
(请参阅$xpath->query()
的第二个参数)。以下是对操作结果的处理:
if (!$comment || !$comment->length) {
throw new UnexpectedValueException('Unable to find comment.');
}
$comment = $comment->item(0);
$line = $comment->getLineNo();
$comment = $comment->textContent;
这应该类似于您在代码中已有的内容,$comment
此处暂时包含注释节点,因此可以从注释中获取行号和文本。
现在更有趣的是如何获取在文档中找到的设备元素$device
的位置。再次使用带有$device
的XPath表达式作为context-node:
$position = $xpath->evaluate("count(preceding::device) + 1", $device);
这非常简单:计算$device
加1之前的设备元素的数量。这是搜索结果的位置。
要完成属性列表,只剩下设备编号或代码:
$number = $device->textContent;
获取所有信息后,可以输出信息:
echo "--------------------------------\n";
echo "Device #" . (1 + $index) . ":\n" .
" Line number: " . $line . "\n" .
" Device position: " . $position . "\n" .
" Device number: " . $number . "\n" .
" Commented number: " . $comment . "\n";
} // foreach
echo "--------------------------------\n";
就是这样。这给出了以下输出:
--------------------------------
Device #1:
Line number: 4
Device position: 1
Device number: J0A0AM049303
Commented number: 100001
--------------------------------
Device #2:
Line number: 7
Device position: 4
Device number: 11C1AJ013635
Commented number: 100004
--------------------------------
使用设备位置,您现在可以通过将其用作XPath中的位置来更加独特地对设备进行寻址:
//device[1]
或
//device[4]
这甚至不像行号那么明显,它还允许您仅使用XPath表达式来解决 device 元素 - 这对于行号是不可能的。
完整示例代码(online demo):
<?php
/**
* http://stackoverflow.com/questions/27717585/resolve-xml-php-node-seach-when-i-give-line-number-as-search-term
*
* 27717585
*/
/**
* xpath string handling xpath 1.0 "quoting"
*
* @param string $input
*
* @return string
*/
function xpath_string($input)
{
if (false === strpos($input, "'")) {
return "'$input'";
}
if (false === strpos($input, '"')) {
return "\"$input\"";
}
return "concat('" . strtr($input, array("'" => '\', "\'", \'')) . "')";
}
$buffer = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
<appConfig authenticate="true"></appConfig>
<device>J0A0AM049303</device><!--100001-->
<device>H0A0AG014628</device><!--100002-->
<device>N0A097016646</device><!--100003-->
<device>11C1AJ013635</device><!--100004-->
</rss>
XML;
$doc = new DOMDocument;
$doc->loadXML($buffer);
$xpath = new DOMXPath($doc);
$searchTerm = "3";
$expression = sprintf("//device[contains(., %s)]", xpath_string($searchTerm));
$devices = $xpath->query($expression);
printf("Search term: %s; found %d device(s):\n", $searchTerm, $devices->length);
foreach ($devices as $index => $device) {
$comment = $xpath->query('following::comment()', $device);
if (!$comment || !$comment->length) {
throw new UnexpectedValueException('Unable to find comment.');
}
$comment = $comment->item(0);
$line = $comment->getLineNo();
$comment = $comment->textContent;
$position = $xpath->evaluate("count(preceding::device) + 1", $device);
$number = $device->textContent;
echo "--------------------------------\n";
echo "Device #" . (1 + $index) . ":\n" .
" Line number: " . $line . "\n" .
" Device position: " . $position . "\n" .
" Device number: " . $number . "\n" .
" Commented number: " . $comment . "\n";
}
echo "--------------------------------\n";