在 PHP 中使用 saveXML 保存 CDATA

Vas*_*Vas 4 php xml

我编写了一个简短的 PHP 脚本来获取现有的 XML 文件,找到一个节点并将其更改为新值。新值必须包装到 CDATA 块中。这工作正常,但是 <> 字符被替换为其各自的 HTML 实体。这破坏了我在 Java 中的 XML 验证。

<?php
$fileName = "whatever";

$doc = new DOMDocument();
$doc->load('test.xml');
$doc->getElementsByTagName("SomeNode")->item(0)->nodeValue = "<![CDATA[".$fileName."]]>";
header('Content-type: text/xml');
$doc->save("test.xml");
echo $doc->saveXML();

?>
Run Code Online (Sandbox Code Playgroud)

这是新 test.xml 的来源:

<?xml version="1.0"?>
<Root>
<FirstNode>
   <SomeNode>&lt;![CDATA[whatever]]&gt;</SomeNode>
</FirstNode>
</Root>
Run Code Online (Sandbox Code Playgroud)

我确实需要 <> 字符而不是它们的 HTML 实体。我怎样才能做到这一点?

更新:我按照建议使用了 createCDATASection() ,但是当我尝试将其保存为节点值时它不起作用(我只是得到一个空白页)。如果我将它附加到 DOM,它会起作用,但这对我没有好处。

$cdata = $doc->createCDATASection( 'whatever' ));
$doc->getElementsByTagName("SomeNode")->item(0)->nodeValue = $cdata;
Run Code Online (Sandbox Code Playgroud)

ThW*_*ThW 6

请勿用于DOMNode::$nodeValue写入值,空字符串除外。它的逃逸被破坏了。节点文本内容的“官方”属性是DOMNode::$textContent

创建 XML 节点有 3 个步骤:

  1. 创建节点
  2. 追加节点
  3. 修改节点(可选)

创建节点

这取决于您要创建的节点。

元素节点:

$element = $document->createElement('nodename');
Run Code Online (Sandbox Code Playgroud)

或者一个文本节点:

$text = $document->createTextNode('<content>');
Run Code Online (Sandbox Code Playgroud)

或者 CDATA 部分:

$cdata = $document->createCDATASection('<content>');
Run Code Online (Sandbox Code Playgroud)

追加节点

现在您已经有了一个节点,您可以将其附加到文档或父元素节点。

$document->appendChild($element);
$element->appendChild($text);
$element->appendChild($cdata);
Run Code Online (Sandbox Code Playgroud)

appendChild() 的结果是附加的节点。所以它可以与create结合起来:

$element = $document->appendChild($document->createElement('nodename'));
Run Code Online (Sandbox Code Playgroud)

修改节点

这主要是针对元素节点完成的。您可以添加属性和子节点。

$element->setAttribute('attr', 'value');
Run Code Online (Sandbox Code Playgroud)

例子

// create the document 
$document = new DOMDocument();

// create the document element node and append it
$element = $document->appendChild($document->createElement('nodename'));
// set an attribute on the element node
$element->setAttribute('attr', 'value');
// add a text node to the element node (escape <>)
$element->appendChild($document->createTextNode('<content>'));
// add a CDATA section to the element node (do not escape <>)
$element->appendChild($document->createCDATASection('<content>'));

echo $document->saveXml();
Run Code Online (Sandbox Code Playgroud)

输出:

<?xml version="1.0"?>
<nodename attr="value">&lt;content&gt;<![CDATA[<content>]]></nodename>
Run Code Online (Sandbox Code Playgroud)

修改现有的 XML

如果您想修改现有的 XML,则需要先获取节点。最有效的方法是 XPath。

它允许您获取节点。就像DOMDocument::getElementByTagName()它会返回一个节点列表一样,但它更加具体和强大。

例子

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXPath($document);

foreach ($xpath->evaluate('/Root/FirstNode/SomeNode[1]') as $someNode) {
  $someNode->nodeValue = '';
  $someNode->appendChild($document->createCDATASection('<content>'));
}
echo $document->saveXml(); 
Run Code Online (Sandbox Code Playgroud)

输出:

<?xml version="1.0"?>
<Root>
  <FirstNode>
    <SomeNode><![CDATA[<content>]]></SomeNode>
  </FirstNode>
</Root>
Run Code Online (Sandbox Code Playgroud)

$someNode->nodeValue = ''。删除元素的所有子节点。这里没有实际内容,因此转义错误不相关。删除子项后,您可以附加一个包含所需内容的新 CDATA 部分。

提示:如果可能的话,尝试使用文本节点,而不是 CDATA 部分。CDATA 部分禁用编码/转义功能。