Reputation: 1683
This seams obvious, but what I found the most was how to manipulate existing XML and now I wish to build from ground zero. The source is a database converted into an Array. The root is a single "menu" and all child elements are called "item". The structure is defined by the value of "parent" property and "code" property.
item[0] ("code"=>"first" "somevar"=>"somevalue")
item[1] ("code"=>"second", "parent"=>"first" "somevar"=>"othervalue")
Means item[1] is a child of item[0].
<menu>
<item code="first" somevar="somevalue">
<item code="second" somevar="othervalue" />
</item>
</menu>
There will be only two levels of items this time, maybe later I'll expand the capabilities to "n" levels...
I tried with SimpleXML, but it seams is too simple. So I tried with DOMDocument, but I'm stuck creating new elements...
$domMenu = new DOMDocument();
$domMenu->createElement("menu");
... creating the $domItem as a DOMElement with attributes ...
$domMenu->menu->appendChild($domItem);
This generates an error, it seams "menu" is not seen as an DOMElement. Should I use getElements methods or there is a better way of build this XML?
Upvotes: 0
Views: 140
Reputation: 19482
You did not append the menu element to the DOM. And DOM does not map element names to object properties like SimpleXML. The root element is accessible using the DOMDocument::$documentElement property.
$domMenu = new DOMDocument();
$domMenu->appendChild(
$menuNode = $domMenu->createElement("menu")
);
... creating the $domItem as a DOMElement with attributes ...
$menuNode->appendChild($domItem);
In you case I would suggest using xpath to find the parent node for the itemNode and if not found let the function call itself (recursion) to append the parent element first. If here is not parent item, append the node to the document element.
$data = [
["code"=>"second", "parent"=>"first", "somevar"=>"othervalue"],
["code"=>"first", "somevar"=>"somevalue"]
];
function appendItem($xpath, $items, $item) {
// create the new item node
$itemNode = $xpath->document->createElement('item');
$itemNode->setAttribute('code', $item['code']);
$itemNode->setAttribute('somevar', $item['somevar']);
$parentCode = isset($item['parent']) ? $item['parent'] : NULL;
// does it have a parent and exists this parent in the $items array
if (isset($parentCode) && isset($items[$parentCode])) {
// fetch the existing parent
$nodes = $xpath->evaluate('//item[@code = "'.$parentCode.'"]');
if ($nodes->length > 0) {
$parentNode = $nodes->item(0);
} else {
// parent node not found create it
$parentNode = appendItem($xpath, $items, $items[$parentCode]);
}
} else {
$parentNode = $xpath->document->documentElement;
}
$parentNode->appendChild($itemNode);
return $itemNode;
}
$dom = new DOMDocument();
$xpath = new DOMXpath($dom);
$dom->appendChild(
$dom->createElement("menu")
);
// build an indexed list using the "code" values
$items = [];
foreach ($data as $item) {
$items[$item['code']] = $item;
}
foreach ($items as $item) {
// check if the item has already been added
if ($xpath->evaluate('count(//item[@code = "'.$item['code'].'"])') == 0) {
// add it
appendItem($xpath, $items, $item);
}
}
$dom->formatOutput = TRUE;
echo $dom->saveXml();
Output:
<?xml version="1.0"?>
<menu>
<item code="first" somevar="somevalue">
<item code="second" somevar="othervalue"/>
</item>
</menu>
Upvotes: 1
Reputation: 3163
$xml = new SimpleXMLElement('<menu/>');
array_walk_recursive($array, array ($xml, 'addChild'));
print $xml->asXML();
Upvotes: 0