SimpleXMLElement在addChild和addAttribute中处理文本值的基本原理

这不是一个不一致的行为? (PHP 5.2.6)

<?php $a = new SimpleXMLElement('<a/>'); $a->addAttribute('b', 'One & Two'); //$a->addChild('c', 'Three & Four'); -- results in "unterminated entity reference" warning! $a->addChild('c', 'Three &amp; Four'); $a->d = 'Five & Six'; print($a->asXML()); 

呈现:

 <?xml version="1.0"?> <ab="One &amp; Two"> <c>Three &amp; Four</c> <d>Five &amp; Six</d> </a> 

在bugs.php.net他们拒绝所有关于这个意见,说这是一个function。 为什么可能呢? 顺便说一下,文档中没有关于SimpleXMLElement转义文本值的差异的内容。

任何人都可以说服我这是最好的APIdevise决定吗?

为了确保我们在同一页面上,您有三种情况。

  1. 使用addAttribute将&符号插入到属性中

  2. 使用addChild将&符号插入到元素中

  3. 通过属性重载将&符号插入到元素中

这是2和3之间的差异,你fl </s>不乐。 为什么addChild不会自动转义&符号,而将属性添加到对象并设置它的值自动地跳过&符号?

基于我的直觉,并受到这个错误的鼓舞,这是一个深思熟虑的devise决定。 财产超负荷($ a-> d ='Five&Six';)的目的是成为“逃避与我并行”的做事方式。 addChild方法的意思是“添加我告诉你添加”的方法。 所以,无论您需要哪种行为,SimpleXML都可以适应您。

假设您有一个文本数据库,其中所有“&”字符都已经被转义。 自动逃脱在这里不适合你。 这就是你使用addChild的地方。 或者让你说你需要在文档中插入一个实体

 $a = simplexml_load_string('<root></root>'); $a->b = 'This is a non-breaking space &nbsp;'; $a->addChild('c','This is a non-breaking space &nbsp;'); print $a->asXML(); 

这就是该错误的PHP开发人员所倡导的。 addChild的行为旨在提供一个“不太简单,更强大”的支持,当您需要在文档中插入&符号而不被转义时。

当然,这确实给我们提供了第一种情况,即addAttribute方法。 addAttribute方法不会转义&符号。 所以,我们现在可能会把这种不一致性说成是

  1. addAttribute方法转义&符号
  2. addChild方法不会转义&符号
  3. 这种行为有点不一致。 用户期望SimpleXML上的方法以一致的方式转义事物是合理的

这就暴露了SimpleXML api的真正问题。 这里的理想情况是

  1. 属性重载元素对象转义&符号
  2. 属性对象的属性重载转义&符号
  3. addChild方法不会转义&符号
  4. addAttribute方法不会转义&符号

这是不可能的,因为SimpleXML没有一个属性对象的概念。 addAttribute方法是(似乎是?)添加属性的唯一方法。 因此,事实certificate(好像?)SimpleXML无法用实体创build属性。

所有这些都揭示了Simple XML的悖论。 这个API背后的想法是提供一个简单的交互方式,事实certificate是复杂的。

团队可以添加一个SimpleXMLAttribute对象,但是这是一个复杂的层次。 如果您想要多个对象层次结构,请使用DomDoument。

团队可以添加标志给addAttribute和addChild方法,但标志会使API更加复杂。

真正的教训在这里? 也许就是这么简单就很难,而且在最后期限上简单就更难了。 我不知道这是否是这种情况,但是对于SimpleXML,似乎有人开始时有一个简单的想法(使用属性重载来简化XML文档的创build),然后在出现问题/function请求时进行调整。

其实我觉得这里真正的教训就是使用JSON;)

这是我的解决scheme,特别是这解决了添加具有相同的标签名称的几个孩子

 $job->addChild('industrycode')->{0} = $entry1; $job->addChild('industrycode')->{0} = $entry2; $job->addChild('industrycode')->{0} = $entry3; 

“假设你有一个文本数据库,所有的&符号都已经逃脱了。”

如果你这样做,你做错了。 数据应以最准确的forms存储,而不是用于当前使用的任何types的输出。 如果实际上在数据库中存储(有效的)HTML数据块,情况会更糟糕。 使用addChild()并再次获取数据将破坏您的HTML; 没有明智的图书馆展示如此可怕的不对称。

addChild()不为您编码文本是完全违反直觉的。 API在什么地方不保护你呢? 这就像json_encode()barfing,如果你在你的值之一使用双引号。

无论如何,要回答原来的问题:显然,我也认为这不是一个好的决定。 我认为这与许多PHP的devise决定是一致的,这是为了实现某人对“更快”的想法,而不是正确的。

字符数据和标记部分提供了转义字符&<的要求,而不是在前面的回答中所述的属性值标准化部分

引用XML Spec 。

除非用作标记分隔符,注释,处理指令或CDATA部分,否则符号字符(&)和左尖括号(<)不能以其文字forms出现,如果在别处需要它们,它们必须使用数字字符引用或string&amp;&lt;分别“

Alan Storm对这个问题有一个很好的描述,但是他所描述的悖论有一个简单的解决scheme。 addChild()方法可以有一个可选的布尔参数来决定是否自动转义字符。 所以,我仍然相信这只是一个(非常)糟糕的deviseselect。

混淆是因为addChild()方法的文档没有引用任何关于这个问题的事实(虽然在讨论中)。 此外,该方法还有一些字符(即小于和大于符号)。 这会误导开发者使用该方法来相信它逃脱了一般的字符。

我相信这是由XML规范要求的属性值规范化引起的。