【问题标题】:How to write CDATA using SimpleXmlElement?如何使用 SimpleXmlElement 编写 CDATA?
【发布时间】: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
  • 你为什么在乎? &lt;title lang="en"&gt;Site Title&lt;/title&gt;&lt;title lang="en"&gt;&lt;![CDATA[Site Title]]&gt;&lt;/title&gt; 是相同的,只是使用更多字节并且更难作为人类阅读。
  • @Quentin 好点。只是客户要求。
  • @Quentin - 使用 CDATA 可以更轻松地编写,因为您不必担心转义任何内容/使其在数据中成为严格的 XML。例如,如果您编写了&lt;title lang="en"&gt;Site&lt;br&gt;Title&lt;/title&gt;,它将破坏 XML 解析器(打开 br 标记而不关闭不是严格的 XML),而 &lt;title lang="en"&gt;&lt;![CDATA[Site&lt;br&gt;Title]]&gt;&lt;/title&gt; 不会。因此,在与客户端打交道时,通常更多只有 CDATA 可读性,而不是所有不稳定的转义所述非 CDATA 节点可能必须包含以避免 CDATA。
  • @JimboJonny — 如果您是手动编写的话,这很好,但问题是关于从 PHP 生成它。

标签: php xml simplexml cdata


【解决方案1】:

知道了!我改编了this great solutionarchived 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-&gt;$element_name = NULL; $this-&gt;$element_name-&gt;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');
        

        【讨论】:

          猜你喜欢
          • 2023-03-05
          • 2011-02-27
          • 2014-10-27
          • 2013-07-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多