0

我需要用 SimpleXML 实现以下算法:

  1. 将 XML 片段字符串放入 SimpleXML 对象;
  2. 遍历所有节点,选择文本节点;
  3. 编辑文本节点(示例转换为大写);
  4. 将 xml 作为字符串返回。

问题:

  • 如何加载带有命名实体的 XML(例如 )。

  • 遍历 XML 以仅获取文本节点...由于$sx->xpath('//text()');无法编辑节点,如何选择要编辑的文本节点?

4

1 回答 1

2

您可以通过分配来覆盖SimpleXML XPath 查询返回的节点的文本内容$node[0],例如

foreach ( $sx->xpath('//text()') as $text_node )
{
    $text_node[0] = 'Hello';
}

但是,请注意,SimpleXML 本身并没有真正表示文本节点,因此如果元素中同时存在子元素和文本,这种循环的行为会很奇怪。

例如,给定 XML ,包含和<a><b>foo<c />bar</b><b>baz quux</b></a>的两个文本节点都将在 SimpleXML 中由第一个元素表示,其全部内容将被替换两次,如下所示(此处为现场演示)。在替换文本中使用计数器变量,我们可以清楚地看到发生了什么 - 期望的输出是,但实际结果是。foobar<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 解析器的包装器),并且您可以使用 and 将使用两个 API 的操作组合在同一个文档上simplexml_import_dom()dom_import_simplexml()同样无需额外开销,因为文档没有不需要重新解析。

这是使用 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();
于 2013-07-13T15:12:43.580 回答