【问题标题】:How to prevent self closing tag in php simplexml如何防止php simplexml中的自闭标签
【发布时间】:2013-11-06 21:44:01
【问题描述】:

我想使用 php simplexml 生成 xml。

$xml = new SimpleXMLElement('<xml/>');

$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');

Header('Content-type: text/xml');
print($xml->asXML());

输出是

<xml>
   <child1>
      <child2>value</child2>
      <noValue/>
   </child1>
</xml>

我想要的是如果标签没有值,它应该像这样显示

<noValue></noValue>

我尝试使用来自Turn OFF self-closing tags in SimpleXML for PHP?LIBXML_NOEMPTYTAG

我试过$xml = new SimpleXMLElement('&lt;xml/&gt;', LIBXML_NOEMPTYTAG);,但它不起作用。所以我不知道把LIBXML_NOEMPTYTAG放在哪里

【问题讨论】:

  • 嗯,它没有告诉你在链接到的页面中放置它的位置吗?
  • 是的,我试过$xml = new SimpleXMLElement('&lt;xml/&gt;', LIBXML_NOEMPTYTAG);,但输出还是一样的&lt;noValue/&gt;
  • Confirmed。编辑:嗯,它似乎与您的 PHP 设置有关。在 3v4l 和 Ideone 上,我仍然得到了自动关闭标签,而在我的本地主机 PHP 5.4 上,我得到了预期的结果。
  • LIBXML_NOEMPTYTAG 仅适用于 DOMDocument,这意味着您需要使用 dom_import_simplexml 才能将您的 simplexml 对象与该选项一起使用。看我的回答。
  • 内容类型显式设置为text/xml 时,严格的 XML 解析器会在遇到空元素时抛出错误。有什么理由这个元素必须是空的并且不能自动关闭?只是好奇这是否是由通用 api 或库强加的(因为它最终应该被修复)

标签: php xml simplexml


【解决方案1】:

既然简单 XML 被证明很麻烦,也许 XMLWriter 可以做你想做的事。

这是fiddle

<?php

$oXMLWriter = new XMLWriter;
$oXMLWriter->openMemory();
$oXMLWriter->startDocument('1.0', 'UTF-8');

$oXMLWriter->startElement('xml');
$oXMLWriter->writeElement('child1', 'Hello world!!');
$oXMLWriter->writeElement('noValue', '');
$oXMLWriter->endElement();

$oXMLWriter->endDocument();
echo htmlentities($oXMLWriter->outputMemory(TRUE));

?>

输出:

<?xml version="1.0" encoding="UTF-8"?>
  <xml>
    <child1>Hello world!!</child1>
    <noValue></noValue>
  </xml>

【讨论】:

  • 谢谢迈克,它有效。但我想将其显示为 xml 页面。我尝试在echo 之前添加Header('Content-type: text/xml');,它是error on line 1 at column 1: Document is empty。如何显示为xml页面?
  • 我添加了 htmlentities() 以便输出完全显示在页面上。添加您的标题并将最后一行更改为echo $oXMLWriter-&gt;outputMemory(TRUE);
  • (psst,不确定您是否标记为迁移this steaming pile of dung,但我认为superuser may put out a hit on you for it
  • @MikeW:啊啊,原来如此!
【解决方案2】:

LIBXML_NOEMPTYTAG 不适用于 simplexml,根据 spec:

此选项目前仅在 DOMDocument::save 和 DOMDocument::saveXML 函数中可用。

要实现您的目标,您需要将 simplexml 对象转换为 DOMDocument 对象:

$xml = new SimpleXMLElement('<xml/>');
$child1 = $xml->addChild('child1');
$child1->addChild('child2', "value");
$child1->addChild('noValue', '');
$dom_sxe = dom_import_simplexml($xml);  // Returns a DomElement object

$dom_output = new DOMDocument('1.0');
$dom_output->formatOutput = true;
$dom_sxe = $dom_output->importNode($dom_sxe, true);
$dom_sxe = $dom_output->appendChild($dom_sxe);

echo $dom_output->saveXML($dom_output, LIBXML_NOEMPTYTAG);

返回:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
  <child1>
    <child2>value</child2>
    <noValue></noValue>
  </child1>
</xml>

值得指出的一点... NOEMPTYTAG 选项可用于 DOMDocument 而不是 simplexml 的可能原因是空元素不被视为有效的 XML,而 DOM 规范允许它们。您正在碰壁以获取无效的 XML,这可能表明有效的自闭合空元素也可以正常工作。

【讨论】:

  • @Wakanina - 不知道我是如何两次发布答案的,但这是我更新的答案,以纠正初始答案中的 DOMELement 错误。
  • Anthony、Mike 和 Passerby:好吧,伙计们,你的答案是正确的,但我更喜欢使用 Anthony 的方法,因为我很容易将它实施到我的应用程序中。我只需要将我的 simplexml 对象转换为 DOMDocument 对象,所以我不会从头开始重建它。谢谢大家:)
  • @Anthony: “空元素不被视为有效的 XML” - 是这样吗?你能给我一些关于这个的建议吗,我想了解更多。
  • “有效”可能不是正确的术语。我相信首选术语是“格式良好”,它有点像鸡/蛋的场景,其中一个空元素 可以 表示为&lt;element&gt;&lt;/element&gt;,但在表示为 @ 时格式正确987654328@ 同时任何空元素都应声明(在 DTD 中)为 EMPTY,这表明元素不能为空,因此如果 &lt;element&gt;data&lt;/element&gt; 有效,&lt;element&gt;&lt;/element&gt; 将不会, 因为第二个表明该元素被声明为 EMPTY 这将使第一个无效。
  • w3.org/TR/REC-xml/#sec-well-formed 是规范中解决空元素概念的部分,尽管我找不到任何地方说明何时允许&lt;element&gt;&lt;/element&gt;(即当非空元素时)可能为空)
【解决方案3】:

从我的 cmets 扩展(有些已被删除):

行为取决于您的环境。同样的代码:

$xml = new SimpleXMLElement('<xml/>', LIBXML_NOEMPTYTAG);

$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');

echo $xml->asXML();

3v4l.orgIdeone.com中,产生自闭标签;
eval.incodepad.org 和我的本地主机(PHP 5.3/5.4、libXML 2.7、Windows)中,它会生成空标签。

由于根据PHP documentLIBXML_NOEMPTYTAG 只能(保证)在DOM 工作,您不妨试试DOM 以确保:

$dom=new DOMDocument("1.0","UTF-8");
$dom->formatOutput=true;
$root=$dom->createElement("xml");
$dom->appendChild($root);
$child1=$dom->createElement("child1");
$root->appendChild($child1);
$node=$dom->createElement("child2");
$node->appendChild($dom->createTextNode("value"));
$child1->appendChild($node);
$node=$dom->createElement("noValue");
$child1->appendChild($node);
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);

3v4l.org demo.

编辑

以上所有在线演示站点默认使用Content-Type: text/plain。如果要直接将 XML 作为独立资源输出到浏览器,可以在输出前指定 header:

header("Content-Type: text/xml");
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);

【讨论】:

    【解决方案4】:

    尽管已经给出了相当冗长的答案——这些答案并不是特别错误,并且确实为一些 libxml 库内部和它的 PHP 绑定提供了一些启示——你最有可能在寻找:

    $output->noValue = '';
    

    添加一个开放标签,空节点值和结束标签(美化,演示在这里:http://3v4l.org/S2PKc):

    <?xml version="1.0"?>
    <xml>
      <child1>
        <child2>value</child2>
        <noValue></noValue>
      </child1>
    </xml>
    

    请注意,现有答案似乎忽略了它。

    【讨论】:

    • 我发现了同样的事情——只需将值设置为空stackoverflow.com/a/29581022/1037948
    • 哦,这很有趣。如果在添加为子元素时将其设置为没有值,则将其视为空元素,但如果将其更新为没有值,则将其视为没有值的非空元素。进一步测试,这甚至适用于$output-&gt;noValue = null;
    • 谢谢!像魅力一样工作:)
    • 这很好,谢谢!
    【解决方案5】:

    我必须获取子节点并为 nodeValue 属性分配一个空字符串,然后出现 xml 关闭标记。

    $output-&gt;childNodes[1]-&gt;nodeValue = '';

    您好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多