我知道这些问题已经存在多个问题,但我找不到足够接近问题的问题。我想解析一些看起来像这样的XML。只有少数元素(可能只有<text/>
将具有混合标记,其余元素都可以使用SimpleXML轻松解析:
<root>
<element>
<text>A <x>b</x> c <y>d</y> e.</text>
</element>
</root>
我已经在大多数结构中使用SimpleXML,但是,当我到达<text/>
元素时,我不知道如何单独阅读这些部分(即&#34; { {1}}&#34;,&#34; A
&#34;&amp;&#34; c
&#34;应为文字e.
&amp; {{ 1}}应该是元素)并按从左到右的顺序。我所能做的就是获得没有标记的所有文本,或者只获取没有文本的子元素。如果在SimpleXML中无法做到这一点,我可以使用DOM或XMLReader实现此目的吗?我一直试图将<x/>
元素转换为DOMNodeList(所以在这个例子中我会有一个包含五个节点的列表)但到目前为止我还没有成功。我到目前为止所尝试的是:
<y/>
似乎不是一个返回特定元素的所有子节点(文本和标签)列表的方法。 PHP中是否有其他类可以完成我忽略的工作?据我所知,到目前为止,SimpleXML只能完全解析XML,其中每个元素只包含文本,只包含其他元素或为空。
答案 0 :(得分:0)
以下代码使用XMLReader,XMLReader::read()
和XMLReader::nodeType
执行我想要的操作:
<?php
$refl = new ReflectionClass('XMLReader');
$xml_consts = $refl->getConstants();
$xml = <<<XML
<root>
<element>
<text>A <x>b</x> c <y>d</y> e.</text>
</element>
</root>
XML;
$reader = new XMLReader();
$reader->XML($xml);
// For validation only
$reader->setParserProperty(XMLReader::VALIDATE, true);
if ($reader->isValid()) {
print("No matter what people say, this XML is valid!\n\n");
}
// Prevent warnings about missing DTD
$reader->setParserProperty(XMLReader::VALIDATE, false);
while ($reader->read()) {
$info = ': ';
switch ($reader->nodeType) {
case XMLReader::TEXT:
$info .= "'$reader->value'";
break;
case XMLReader::ELEMENT:
$info .= "<$reader->name>";
break;
case XMLReader::END_ELEMENT:
$info .= "</$reader->name>";
break;
default:
$info = '';
}
print(array_search($reader->nodeType, $xml_consts) . $info . PHP_EOL);
}
?>
输出:
No matter what people say, this XML is valid!
ELEMENT: <root>
SIGNIFICANT_WHITESPACE
ELEMENT: <element>
SIGNIFICANT_WHITESPACE
ELEMENT: <text>
TEXT: 'A '
ELEMENT: <x>
TEXT: 'b'
END_ELEMENT: </x>
TEXT: ' c '
ELEMENT: <y>
TEXT: 'd'
END_ELEMENT: </y>
TEXT: ' e.'
END_ELEMENT: </text>
SIGNIFICANT_WHITESPACE
END_ELEMENT: </element>
SIGNIFICANT_WHITESPACE
END_ELEMENT: </root>
答案 1 :(得分:0)
您也可以使用DOM + Xpath。以下示例遍历所有元素和文本节点。这种方式的好处是,您可以将任何节点用作其他Xpath表达式的上下文。
$xml = <<<'XML'
<root>
<element>
<text>A <x>b</x> c <y>d</y> e.</text>
</element>
</root>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXpath($dom);
$nodes = $xpath->evaluate(
'//*|//text()[normalize-space(.) != ""]'
);
foreach ($nodes as $node) {
switch ($node->nodeType) {
case XML_ELEMENT_NODE :
var_dump("ELEMENT: ".$node->localName);
break;
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
var_dump("TEXT: ".$node->textContent);
break;
}
}
string(13) "ELEMENT: root"
string(16) "ELEMENT: element"
string(13) "ELEMENT: text"
string(8) "TEXT: A "
string(10) "ELEMENT: x"
string(7) "TEXT: b"
string(9) "TEXT: c "
string(10) "ELEMENT: y"
string(7) "TEXT: d"
string(9) "TEXT: e."