如何使用 SimpleXmlElement 编写 CDATA?
Posted
技术标签:
【中文标题】如何使用 SimpleXmlElement 编写 CDATA?【英文标题】:How to write CDATA using SimpleXmlElement? 【发布时间】:2011-09-09 18:05:50 【问题描述】:我有这个代码来创建和更新 xml 文件:
<?php
$xmlFile = 'config.xml';
$xml = new SimpleXmlElement('<site/>');
$xml->title = 'Site Title';
$xml->title->addAttribute('lang', 'en');
$xml->saveXML($xmlFile);
?>
这会生成以下 xml 文件:
<?xml version="1.0"?>
<site>
<title lang="en">Site Title</title>
</site>
问题是:有没有办法用这种方法/技术添加CDATA来创建下面的xml代码?
<?xml version="1.0"?>
<site>
<title lang="en"><![CDATA[Site Title]]></title>
</site>
【问题讨论】:
看起来 SimpleXML 不支持创建 CDATA 节点。改用DOM 你为什么在乎?<title lang="en">Site Title</title>
和 <title lang="en"><![CDATA[Site Title]]></title>
是相同的,只是使用更多字节并且更难作为人类阅读。
@Quentin 好点。只是客户要求。
@Quentin - 使用 CDATA 可以更轻松地编写,因为您不必担心转义任何内容/使其在数据中成为严格的 XML。例如,如果您编写了<title lang="en">Site<br>Title</title>
,它将破坏 XML 解析器(打开 br 标记而不关闭不是严格的 XML),而 <title lang="en"><![CDATA[Site<br>Title]]></title>
不会。因此,在与客户端打交道时,通常更多只有 CDATA 可读性,而不是所有不稳定的转义所述非 CDATA 节点可能必须包含以避免 CDATA。
@JimboJonny — 如果您是手动编写的话,这很好,但问题是关于从 PHP 生成它。
【参考方案1】:
知道了!我改编了this great solution(archived version)的代码:
<?php
// http://coffeerings.posterous.com/php-simplexml-and-cdata
class SimpleXMLExtended extends SimpleXMLElement
public function addCData($cdata_text)
$node = dom_import_simplexml($this);
$no = $node->ownerDocument;
$node->appendChild($no->createCDATASection($cdata_text));
$xmlFile = 'config.xml';
// instead of $xml = new SimpleXMLElement('<site/>');
$xml = new SimpleXMLExtended('<site/>');
$xml->title = NULL; // VERY IMPORTANT! We need a node where to append
$xml->title->addCData('Site Title');
$xml->title->addAttribute('lang', 'en');
$xml->saveXML($xmlFile);
?>
生成的 XML 文件:
<?xml version="1.0"?>
<site>
<title lang="en"><![CDATA[Site Title]]></title>
</site>
谢谢Petah
【讨论】:
public function addChildcdata($element_name, $cdata) $this->$element_name = NULL; $this->$element_name->addCData($cdata);
扩展类中添加的这个函数可以让你直接追加CData。
我可以添加我的 2c,当您加载文件 simplexml_load_file/string()
时,您可以简单地为它提供一个选项“LIBXML_NOCDATA”? php.net/manual/en/libxml.constants.php【参考方案2】:
这是我的这个类的版本,它有一个快速的 addChildWithCDATA 方法,基于your answer:
Class SimpleXMLElementExtended extends SimpleXMLElement
/**
* Adds a child with $value inside CDATA
* @param unknown $name
* @param unknown $value
*/
public function addChildWithCDATA($name, $value = NULL)
$new_child = $this->addChild($name);
if ($new_child !== NULL)
$node = dom_import_simplexml($new_child);
$no = $node->ownerDocument;
$node->appendChild($no->createCDATASection($value));
return $new_child;
像这样简单地使用它:
$node = new SimpleXMLElementExtended();
$node->addChildWithCDATA('title', 'Text that can contain any unsafe XML charachters like & and <>');
【讨论】:
【参考方案3】:如果您不想扩展 SimpleXMLElement,您也可以为此创建一个辅助函数:
/**
* Adds a CDATA property to an XML document.
*
* @param string $name
* Name of property that should contain CDATA.
* @param string $value
* Value that should be inserted into a CDATA child.
* @param object $parent
* Element that the CDATA child should be attached too.
*/
$add_cdata = function($name, $value, &$parent)
$child = $parent->addChild($name);
if ($child !== NULL)
$child_node = dom_import_simplexml($child);
$child_owner = $child_node->ownerDocument;
$child_node->appendChild($child_owner->createCDATASection($value));
return $child;
;
【讨论】:
【参考方案4】: class MySimpleXMLElement extends SimpleXMLElement
public function addChildWithCData($name , $value)
$new = parent::addChild($name);
$base = dom_import_simplexml($new);
$docOwner = $base->ownerDocument;
$base->appendChild($docOwner->createCDATASection($value));
$simpleXmlElemntObj = new MySimpleXMLElement('<site/>');
/* USAGE */
/* Standard */
$simpleXmlElemntObj->addChild('Postcode','1111');
/* With CDATA */
$simpleXmlElemntObj->addChildWithCData('State','Processing');
/* RESULT */
/*
<?xml version="1.0"?>
<site>
<Postcode>1111</Postcode>
<State><![CDATA[Processing]]></State>
</site>
*/
【讨论】:
【参考方案5】:这是我使用 CDATA 添加子节点或将 CDATA 添加到节点的组合解决方案。
class SimpleXMLElementExtended extends SimpleXMLElement
/**
* Add value as CData to a given XML node
*
* @param SimpleXMLElement $node SimpleXMLElement object representing the child XML node
* @param string $value A text to add as CData
* @return void
*/
private function addCDataToNode(SimpleXMLElement $node, $value = '')
if ($domElement = dom_import_simplexml($node))
$domOwner = $domElement->ownerDocument;
$domElement->appendChild($domOwner->createCDATASection("$value"));
/**
* Add child node with value as CData
*
* @param string $name The child XML node name to add
* @param string $value A text to add as CData
* @return SimpleXMLElement
*/
public function addChildWithCData($name = '', $value = '')
$newChild = parent::addChild($name);
if ($value) $this->addCDataToNode($newChild, "$value");
return $newChild;
/**
* Add value as CData to the current XML node
*
* @param string $value A text to add as CData
* @return void
*/
public function addCData($value = '')
$this->addCDataToNode($this, "$value");
// Usage example:
$xml_doc = '<?xml version="1.0" encoding="utf-8"?>
<offers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1">
</offers>';
$xml = new SimpleXMLElementExtended($xml_doc);
$offer = $xml->addChild('o');
$offer->addAttribute('id', $product->product_id);
$offer->addAttribute('url', 'some url');
$cat = $offer->addChildWithCData('cat', 'Category description as CDATA');
// or
$cat = $offer->addChild('cat');
$cat->addCData('Category description as CDATA');
【讨论】:
以上是关于如何使用 SimpleXmlElement 编写 CDATA?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用其父级的情况下设置 SimpleXmlElement 的文本值?
如何打印 SimpleXMLElement 对象的特定数组元素
如何在 PHP 中回显此 SimpleXMLElement 中的 OK 属性? [复制]