我有一个SimpleXMLElement对象$ child和一个SimpleXMLElement对象$ parent。
如何将$ child添加为$ parent的子级?有没有办法在不转换为DOM的情况下执行此操作?
addChild()方法似乎只允许我创建一个新的空元素,但是当我想添加$ child的元素也有子元素时,这没有用。我想我可能需要递归。
答案 0 :(得分:7)
不幸的是SimpleXMLElement
没有提供将两个元素组合在一起的任何内容。如@nickf wrote,它更适合阅读而非操纵。但是,姐妹扩展程序DOMDocument
用于编辑,您可以通过dom_import_simplexml()
将它们组合在一起。 @salathe shows in a related answer这对于特定的SimpleXMLElements是如何工作的。
以下显示了如何使用输入检查和更多选项。我用两个例子来做。第一个示例是插入XML字符串的函数:
/**
* Insert XML into a SimpleXMLElement
*
* @param SimpleXMLElement $parent
* @param string $xml
* @param bool $before
* @return bool XML string added
*/
function simplexml_import_xml(SimpleXMLElement $parent, $xml, $before = false)
{
$xml = (string)$xml;
// check if there is something to add
if ($nodata = !strlen($xml) or $parent[0] == NULL) {
return $nodata;
}
// add the XML
$node = dom_import_simplexml($parent);
$fragment = $node->ownerDocument->createDocumentFragment();
$fragment->appendXML($xml);
if ($before) {
return (bool)$node->parentNode->insertBefore($fragment, $node);
}
return (bool)$node->appendChild($fragment);
}
此示例性函数允许附加XML或将其插入某个元素(包括根元素)之前。在确定是否有要添加的内容之后,它使用 DOMDocument 函数和方法将XML作为文档片段插入,它也在How to import XML string in a PHP DOMDocument中列出。用法示例:
$parent = new SimpleXMLElement('<parent/>');
// insert some XML
simplexml_import_xml($parent, "\n <test><this>now</this></test>\n");
// insert some XML before a certain element, here the first <test> element
// that was just added
simplexml_import_xml($parent->test, "<!-- leave a comment -->\n ", $before = true);
// you can place comments above the root element
simplexml_import_xml($parent, "<!-- this works, too -->", $before = true);
// but take care, you can produce invalid XML, too:
// simplexml_add_xml($parent, "<warn><but>take care!</but> you can produce invalid XML, too</warn>", $before = true);
echo $parent->asXML();
这给出了以下输出:
<?xml version="1.0"?>
<!-- this works, too -->
<parent>
<!-- leave a comment -->
<test><this>now</this></test>
</parent>
第二个例子是插入SimpleXMLElement
。如果需要,它会使用第一个功能。它基本上检查是否有任何事情要做,以及要导入哪种元素。如果它是一个属性,它只会添加它,如果它是一个元素,它将被序列化为XML,然后作为XML添加到父元素:
/**
* Insert SimpleXMLElement into SimpleXMLElement
*
* @param SimpleXMLElement $parent
* @param SimpleXMLElement $child
* @param bool $before
* @return bool SimpleXMLElement added
*/
function simplexml_import_simplexml(SimpleXMLElement $parent, SimpleXMLElement $child, $before = false)
{
// check if there is something to add
if ($child[0] == NULL) {
return true;
}
// if it is a list of SimpleXMLElements default to the first one
$child = $child[0];
// insert attribute
if ($child->xpath('.') != array($child)) {
$parent[$child->getName()] = (string)$child;
return true;
}
$xml = $child->asXML();
// remove the XML declaration on document elements
if ($child->xpath('/*') == array($child)) {
$pos = strpos($xml, "\n");
$xml = substr($xml, $pos + 1);
}
return simplexml_import_xml($parent, $xml, $before);
}
此示例性函数对Simplexml中常见的元素和属性列表进行规范化。您可能希望将其更改为一次插入多个SimpleXMLElements,但正如下面的用法示例所示,我的示例不支持(请参阅属性示例):
// append the element itself to itself
simplexml_import_simplexml($parent, $parent);
// insert <this> before the first child element (<test>)
simplexml_import_simplexml($parent->children(), $parent->test->this, true);
// add an attribute to the document element
$test = new SimpleXMLElement('<test attribute="value" />');
simplexml_import_simplexml($parent, $test->attributes());
echo $parent->asXML();
这是第一个用法示例的延续。因此现在的输出是:
<?xml version="1.0"?>
<!-- this works, too -->
<parent attribute="value">
<!-- leave a comment -->
<this>now</this><test><this>now</this></test>
<!-- this works, too -->
<parent>
<!-- leave a comment -->
<test><this>now</this></test>
</parent>
</parent>
我希望这会有所帮助。您可以find the code in a gist和online demo / PHP version overview。
答案 1 :(得分:6)
我知道这不是最有用的答案,但特别是因为你正在创建/修改XML,我会切换到使用DOM函数。 SimpleXML适用于访问简单文档,但在更改它们方面却很差。
如果SimpleXML在所有其他地方善待您,并且您想坚持使用它,您仍然可以选择暂时跳转到DOM功能以执行您需要的操作然后再使用{{3 }和dom_import_simplexml()
。我不确定这是多么有效,但它可能会帮助你。
答案 2 :(得分:-1)
实际上,如果仔细查看addChild()
的定义方式,则可以(动态)。我使用这种技术使用递归和传递引用
addChild()
返回已添加孩子的SimpleXMLElement
。$xml->addChilde($nodeName, $nodeValue)
。$xml->addChilde($nodeName)
,没有值传递给addChild()
。这个
将导致具有SimpleXMLElement类型的子节点!不是
串<!/ LI>
目标XML
<root>
<node>xyz</node>
<node>
<node>aaa</node>
<node>bbb</node>
</node>
</root>
<强>代码:强>
$root = new SimpleXMLElement('<root />');
//add child with name and string value.
$root.addChild('node', 'xyz');
//adds child with name as root of new SimpleXMLElement
$sub = $root->addChild('node');
$sub.addChild('node', 'aaa');
$sub.addChild('node', 'bbb');
答案 3 :(得分:-2)
离开这里,因为我偶然发现了这个页面,发现SimpleXML现在通过::addChild method支持这个功能。
您也可以使用此方法添加任何级联元素:
$xml->addChild('parent');
$xml->parent->addChild('child');
$xml->parent->child->addChild('child_id','12345');