我需要用SimpleXML:实现以下算法
- 将XML片段字符串放入SimpleXML对象中
- 遍历所有节点,选择文本节点
- 编辑文本节点(例如转换为大写)
- 以字符串形式返回xml
问题:
-
如何加载带有命名实体的XML(例如
)。 -
若要遍历XML以仅获取文本节点。。。使用
$sx->xpath('//text()');
我无法编辑节点,如何选择要编辑的文本节点?
您可以通过分配给$node[0]
来覆盖SimpleXML XPath查询返回的节点的文本内容,例如
foreach ( $sx->xpath('//text()') as $text_node )
{
$text_node[0] = 'Hello';
}
但是,请注意,SimpleXML本身并没有文本节点的表示形式,因此如果元素中同时存在子元素和文本,则这种循环的行为会很奇怪。
例如,给定XML <a><b>foo<c />bar</b><b>baz quux</b></a>
,包含foo
和bar
的两个文本节点都将在SimpleXML中由第一个<b>
元素表示,其整个内容将被'Hello'
替换两次,如下所示(此处为实时演示)。在替换文本中使用计数器变量,我们可以清楚地看到发生了什么——期望的输出是<a><b>Hello 1<c />Hello 2</b><b>Hello 3</b></a>
,但实际结果是<a><b>Hello 2</b><b>Hello 3</b></a>
。
$sx = simplexml_load_string('<a><b>foo<c />bar</b><b>baz quux</b></a>');
$counter = 1;
foreach ( $sx->xpath('//text()') as $text_node )
{
$text_node[0] = 'Hello ' . $counter++;
}
echo $sx->asXML();
这种操作,至少在构建问题时(找到文本节点,而不是在特定的元素集上迭代,可能是递归的),更适合于DOM API,而不是SimpleXML。请记住,这两者之间没有性能差异(它们都是围绕同一XML解析器的包装器),并且您可以通过使用simplexml_import_dom()
和dom_import_simplexml()
在同一文档上组合使用这两个API的操作,同样不需要额外的开销,因为文档不需要重新解析。
下面是通过混合使用SimpleXML和DOM(实时演示)修复的上述示例。如果这是整个代码,您可以直接使用DOM进行解析,但这表明,如果您已经有其他代码使用SimpleXML操作此文档,那么它们是多么容易混合。请注意,最后,我们使用原始的SimpleXML对象输出XML——我们不需要运行simplexml_import_dom($dom)
,因为这两个对象都引用了内存中相同的解析"文档"。
$sx = simplexml_load_string('<a><b>foo<c />bar</b><b>baz quux</b></a>');
$dom = dom_import_simplexml($sx);
$counter = 1;
$xpath = new DOMXpath($dom->ownerDocument);
foreach ( $xpath->query('//text()') as $text_node )
{
$text_node->nodeValue = 'Hello ' . $counter++;
}
echo $sx->asXML();