我不得不重写程序的一部分,使用XMLReader选择XML文件的一部分进行处理。
以这个简化的XML为例:
<odds>
<sport>
<region>
<group>
<event name="English Championship 2014-15" eventid="781016.1">
<bet name="Kazanan" betid="12377108.1">
<selection selectionid="52411062.1"/>
</selection>
</bet>
</event>
</group>
</region>
</sport>
</odds>
此次致电xpath()
:
$bets = $xml->xpath(
"//odds/sport/region/group/event/bet/selection[contains(@selectionid,'".$selectionToFind."')]/.."
);
将选择整个<bet>
节点及其子节点(<selection>
节点)。
但是,我的代码只选择一个具有给定<selection>
的{{1}}节点:
selectionid
如何使用$reader = new XMLReader;
$reader->open('file.xml');
while($reader->read()) {
$event = $reader->getAttribute($value);
if ($event == 781016.1 ) {
$node = new SimpleXMLElement($reader->readOuterXML());
var_dump($node);
break;
}
}
复制xpath()
的行为,以便我选择XMLReader
节点及其子节点而不仅仅是一个<bet>
子节点?
我想这个问题归结为:我可以通过子项的属性值选择整个父节点<selection>
,例如<bet>
?
答案 0 :(得分:1)
[忽略SimpleXML解决方案并向下看XMLReader一个]
我建议使用SimpleXMLElement :: xpath方法。
http://php.net/manual/en/simplexmlelement.xpath.php
$xml = new SimpleXMLElement($xml_string);
/* Search for <a><b><c> */
$result = $xml->xpath("/odds/sport/region/group/event/bet");
$ result将包含所有“打赌”的孩子。注意:
// XMLReader解决方案**********************
$reader = new XMLReader;
$reader->open('file.xml');
$parent_element = null;
while($reader->read()) {
$selectionid = $reader->getAttribute('selectionid');
if ($selectionid == '52411062.1' ) {
// use the parent of the node with attribute 'selectionid' = '52411062.1'
$node = $parent_element;
var_dump($node);
break;
}
elseif ($reader->name === 'bet') { )
{
// store parent element
$parent_element = new SimpleXMLElement($reader->readOuterXML());
}
}
答案 1 :(得分:0)
DOMXPath
在性能方面比SimpleXML
更强大(它有其他优点,例如它可以正确处理命名空间)。有关PHP中几个XPath库的讨论,请参阅示例this IBM article。
在使用DOMXPath
时,如果您的性能问题仍然存在(或仍然严重),我很好奇:
<?php
$doc = new DOMDocument;
$doc->load('sample.xml');
$xpath = new DOMXPath($doc);
$nodes = $xpath->query("/odds/sport/region/group/event/bet[selection/@selectionid = '52411062.1']");
foreach ($nodes as $node)
{
print $xml = $node->ownerDocument->saveXML($node);
}
?>
结果是将您显示的小片段作为输入
<bet name="Kazanan" betid="12377108.1">
<selection selectionid="52411062.1"/>
</bet>
如果这没有帮助,你真的不得不求助于一个基于事件的(拉式)XML解析器,它不会将整个文档读入内存 - 正如Yasen所暗示的那样。
答案 2 :(得分:0)
XMLReader可以expand()
将当前节点转换为DOMNode
。这将仅将节点及其后代加载到内存中。
之后,您可以使用DOMXPath
实例或将节点转换为SimpleXMLElement
。
$reader = new XMLReader();
$reader->open('data:/text/xml,'.urlencode($xml));
$dom = new DOMDocument();
$xpath = new DOMXpath($dom);
while($reader->read()) {
if (
$reader->nodeType == XMLReader::ELEMENT &&
$reader->localName == 'bet'
) {
$bet= $reader->expand($dom);
if ($xpath->evaluate('count(selection[@selectionid = "52411062.1"]) > 0', $bet)) {
var_dump($dom->saveXml($bet));
}
}
}
您将始终必须决定在XMLReader中实现哪个部分以及在DOM / SimpleXML中实现哪个部分。在XMLReader中,您必须验证节点并维护状态,但可以避免加载数据。在解析的某个时刻,XML片段将足够小,您可以使用expand()
。