在PHP中使用saveXML保存CDATA

时间:2015-05-11 21:24:14

标签: php xml

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

Employee emp = new Manager();

这是新test.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();

?>

我真的需要&lt;&gt;字符而不是HTML实体。我怎么能做到这一点?

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

<?xml version="1.0"?>
<Root>
<FirstNode>
   <SomeNode>&lt;![CDATA[whatever]]&gt;</SomeNode>
</FirstNode>
</Root>

2 个答案:

答案 0 :(得分:4)

除了空字符串外,不要使用DOMNode::$nodeValue来写入值。逃跑打破了。创建XML节点有3个步骤:

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

创建节点

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

元素节点:

$element = $document->createElement('nodename');

或文本节点:

$text = $document->createTextNode('<content>');

或CDATA部分:

$cdata = $document->createCDATASection('<content>');

追加节点

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

$document->appendChild($element);
$element->appendChild($text);
$element->appendChild($cdata);

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

结合使用
$element = $document->appendChild($document->createElement('nodename'));

修改节点

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

$element->setAttribute('attr', 'value');

实施例

// 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();

输出:

<?xml version="1.0"?>
<nodename attr="value">&lt;content&gt;<![CDATA[<content>]]></nodename>

修改现有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(); 

输出:

<?xml version="1.0"?>
<Root>
  <FirstNode>
    <SomeNode><![CDATA[<content>]]></SomeNode>
  </FirstNode>
</Root>

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

提示:尽可能使用文本节点,而不是CDATA部分。 CDATA部分禁用编码/转义功能。

答案 1 :(得分:2)

我们说你的test.xml文件是

<?xml version="1.0"?>
<Root>
    <FirstNode>
        <SomeNode>a</SomeNode>
    </FirstNode>
</Root>

你有两种可能性:
或者你想要添加SomeNode

<SomeNode>
    a
    <![CDATA[whatever]]>
</SomeNode>

然后你就可以这样做:

$cdata = $doc->createCDATASection( 'whatever' );
$doc->getElementsByTagName("SomeNode")
    ->item(0)
    ->appendChild($cdata);

或者您想在SomeNode中替换

<SomeNode>
    <![CDATA[whatever]]>
</SomeNode>

然后你可以这样做:

$cdata = $doc->createCDATASection( 'whatever' );
$oldNode = $doc->getElementsByTagName("SomeNode")
               ->item(0);
$oldNode->parentNode
        ->replaceChild($cdata,$oldNode);