我编写了一个简短的 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><![CDATA[whatever]]></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)
请勿用于DOMNode::$nodeValue写入值,空字符串除外。它的逃逸被破坏了。节点文本内容的“官方”属性是DOMNode::$textContent。
创建 XML 节点有 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"><content><![CDATA[<content>]]></nodename>
Run Code Online (Sandbox Code Playgroud)
如果您想修改现有的 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 部分禁用编码/转义功能。