有没有办法使用XMLReader获得第一行?

时间:2019-08-08 22:42:10

标签: php xml xml-parsing xmlreader

有没有一种方法可以在PHP中使用xmlreader获取元素的开始标记?

我有这种类型的xml:

<Product id="L20" manufacturer="A">
    <Description>Desc</Description>
    <Price>5.00</Price>
</Product>

这是我的代码。 $ reader是XMLReader类型。

while($reader->read()) {
    if($reader->nodeType == XMLReader::ELEMENT) {
        //??
    }
}

我希望它获得<Product id="L20" manufacturer="A">作为输出。

我想指定要使用XMLReader。当其他人使用DOM或simpleXML时,不要再暗示它是其他人的重复。我有一个很大的XML文件,在当前系统上无法将其全部存储到内存中。

1 个答案:

答案 0 :(得分:0)

您将需要使用XMLReader方法读取节点的名称和属性。似乎尚未为属性节点实现XMLReader::readString(),因此您需要收集名称,导航回元素并使用XMLReader::getAttribute()

$xml = <<<'XML'
<Product id="L20" manufacturer="A">
    <Description>Desc</Description>
    <Price>5.00</Price>
</Product>
XML;

$reader = new XMLReader();
$reader->open('data://text/plain;base64,' . base64_encode($xml));

while ($reader->read()) {
    if ($reader->nodeType === XMLReader::ELEMENT && $reader->localName === 'Product') {
        var_dump($reader->localName);
        $attributeNames = [];
        $found = $reader->moveToFirstAttribute();
        while ($found && $reader->nodeType === XMLReader::ATTRIBUTE) {
            $attributeNames[] = $reader->localName;
            $found = $reader->moveToNextAttribute();
        }
        $reader->moveToElement();
        var_dump(
            array_combine(
                $attributeNames,
                array_map(
                    function($name) use ($reader) {
                        return $reader->getAttribute($name);
                    },
                    $attributeNames,
                )
            )
        );
    }
}

输出:

string(7) "Product"
array(2) {
  ["id"]=>
  string(3) "L20"
  ["manufacturer"]=>
  string(1) "A"
}

可以将XMLReader与DOM结合使用。大型XML文件通常是项目列表。您可以使用XMLReader查找item节点,并将其扩展为DOM以获取更复杂的内容。如果XML是Product节点的列表,则可以迭代和扩展它们。它将仅将Product节点及其后代立即加载到内存中,允许您使用DOM方法和Xpath表达式。

$xml = <<<'XML'
<Products>
<Product id="L20" manufacturer="A">
    <Description>Desc</Description>
    <Price>5.00</Price>
</Product>
<Product id="L30" manufacturer="B">
    <Description>Desc</Description>
    <Price>5.00</Price>
</Product>
</Products>
XML;

$reader = new XMLReader();
$reader->open('data://text/plain;base64,' . base64_encode($xml));

// a document to expand to
$document = new DOMDocument();

while ($reader->read() && $reader->localName !== 'Product') {

}

while ($reader->nodeType === XMLReader::ELEMENT && $reader->localName === 'Product') {
    $productNode = $reader->expand($document);
    var_dump($productNode->localName);
    var_dump(
        array_map(
            function($node) {
                return $node->textContent;
            },
            iterator_to_array($productNode->attributes)
        )
    );

    // next Product sibling
    $reader->next('Product');
}

输出:

string(7) "Product"
array(2) {
  ["id"]=>
  string(3) "L20"
  ["manufacturer"]=>
  string(1) "A"
}
string(7) "Product"
array(2) {
  ["id"]=>
  string(3) "L30"
  ["manufacturer"]=>
  string(1) "B"
}