Add nodes to SimpleXMLElement
Ford Prefect: You know, it’s at times like this, when I’m trapped in a Vogon airlock with a man from Betelgeuse, and about to die of asphyxiation in deep space, that I really wish I’d listened to what my mother told me when I was young.
Arthur Dent: Why, what did she tell you?
Ford Prefect: I don’t know, I didn’t listen. — Douglas Adams (The Hitchhiker’s Guide to the Galaxy)
One of the things I tell our developers is that when a solution starts becoming unbearably complex you’re probably looking at it the wrong way. An obvious example from just this week is that it’s difficult if not impossible to automatically style a border to the right of every element in a list except for the last one, but it’s very easy to style a border to the left of every element except for the first one.
I should listen to myself more often. I just spent far too much time trying to figure out how to create a new node in PHP’s SimpleXML and add it as a child to an existing node.
I have a simple array that I want to serialize into somewhat future-proofed, readable text for storage in a database. XML seemed like the obvious solution. The array contains a dictionary-like list of fields and values. Some of those values can be arrays themselves, but those will be simple one-dimensional lists, and none of the array values will themselves be arrays—the rabbit hole only goes two deep at most.
Adding the non-arrays was easy using SimpleXMLElement::addChild. Creating a list of elements was easy enough, too, creating a new SimpleXMLElement and adding items to it. But adding that list to the parent seemed impossible.
[toggle code]
-
function arrayToXML($myArray) {
- $arrayXML = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><fields />');
-
foreach ($myArray as $field=>$value) {
-
if (is_array($value)) {
- //this is a list, and needs to have several items
- $list = new SimpleXMLElement("<$field />");
-
foreach ($value as $item) {
- $list->addChild('item', $item);
- }
- //there is no such function by any name in SimpleXML
- $arrayXML->appendChild($list);
-
} else {
- //scalar, so just add it directly
- $arrayXML->addChild($field, $value);
- }
-
if (is_array($value)) {
- }
- return $arrayXML->asXML();
- }
First I looked all over for a built-in method to add an existing node to a parent element; all I could find was people overriding SimpleXMLElement in complex ways. Then I discovered that SimpleXMLElements can be accessed simultaneously as DOM elements—but discovered that nodes can’t be added to orphan nodes.
There was no way that something called “SimpleXML” could be so complex for such obvious functionality.
I had just about given up when I noticed some pale green text I’d missed: addChild, which was working fine for me, returned a SimpleXMLElement. The correct solution was not to create a child and add it to the parent. The correct solution is to add the child to the parent, and then create it.
[toggle code]
-
function arrayToXML($myArray) {
- $arrayXML = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><fields />');
-
foreach ($myArray as $field=>$value) {
-
if (is_array($value)) {
- //this is a list, and needs to have several items
- //so first add the child
- $list = $arrayXML->addChild($field);
- //and then populate the child
-
foreach ($value as $item) {
- $list->addChild('item', $item);
- }
-
} else {
- //scalar, so just add it directly
- $arrayXML->addChild($field, $value);
- }
-
if (is_array($value)) {
- }
- return $arrayXML->asXML();
- }
Duh.
- SimpleXML
- “The SimpleXML extension provides a very simple and easily usable toolset to convert XML to an object that can be processed with normal property selectors and array iterators.”
More Duh
- ModelForms and FormViews
- This is just a notice because when I did a search, nothing came up. Don’t use ModelForm with FormView, use UpdateView instead.
- minidom self-closes empty SCRIPT tags
- Python’s minidom will self-close empty script tags—as it should. But it turns out that Firefox 3.6 and IE 8 don’t support empty script tags.
- Django using too much memory? Turn off DEBUG=True!
- DEBUG=False can save hundreds of megabytes in Django command-line scripts, and probably in Django web processes.
- No distutils? Install Xcode
- If Distutils is not available on Mac OS X Leopard, install the Xcode developer tools. Also, the upgrade process I followed for upgrading from Mailman 2.1.9 to 2.1.12.
- Django QuerySet Heisenberg gotcha
- Observing a system changes the system. That’s especially true with Django’s QuerySet API.
More PHP
- Auto-closing HTML tags in comments
- One of the biggest problems on blogs is that comments often get stuck with unclosed italics, bold, or links. You can automatically close them by transforming the HTML snippet into an XML document.
- Stable sorting of numerically indexed arrays in PHP
- From PHP 4.1, sorted arrays are no longer “stable”. That is, if they are resorted and two items are equal values, they no longer can be expected to maintain their order vis-a-vis each other.
- Override the Host: header when using PHP’s readfile
- It is possible to specify HTTP headers when using URLs with PHP’s file-oriented functions such as readfile.
- Web display of Taskpaper file
- It is easy to use PHP to convert a Taskpaper task file into simple HTML conducive to styling via CSS.
- New PHP Tutorial
- I’ve just uploaded a new version of my PHP tutorial, with a better MySQL section.
- Two more pages with the topic PHP, and other related pages
More XML
- Catalina: iTunes Library XML
- What does Catalina mean for 42 Astounding Scripts?
- Parsing JSKit/Echo XML using PHP
- In the comments, dpusa wants to import JSKit comments into WordPress, which uses PHP. Here’s how to parse them using PHP.
- Parsing JSKit/Echo XML comments files
- While I’m not a big fan of remote comment systems for privacy reasons, I was willing to use JSKit as a temporary solution because they provide an easy XML dump of posted comments. This weekend, I finally moved my main blog to custom comments; here’s how I parsed JSKit’s XML file.
- Auto-closing HTML tags in comments
- One of the biggest problems on blogs is that comments often get stuck with unclosed italics, bold, or links. You can automatically close them by transforming the HTML snippet into an XML document.
- minidom self-closes empty SCRIPT tags
- Python’s minidom will self-close empty script tags—as it should. But it turns out that Firefox 3.6 and IE 8 don’t support empty script tags.
- Five more pages with the topic XML, and other related pages
October 31, 2009: I updated the base SimpleXMLElement to be UTF-8; without the “<?xml version="1.0" encoding="UTF-8"?>” declaration, it defaults to whatever happens to be the default in the PHP you’re using, which isn’t necessarily going to match what the database this will be stored in is using, nor what the web page this appears in is using.