tags:

views:

66

answers:

3
+2  Q: 

Split XML in PHP

I have a merged xml with a root element and multiple item child elements. Something like this

 <root>
  <item>test1</item>
  <item>test2</item>
 </root>

What I want is an easy way to parse the xml and create an array of xml strings from the items.

$arrXml[0] = '<item>test1</item>';
$arrXml[1] = '<item>test2</item>';

I'm looking for an elegant solution not any solution.

+1  A: 

Have you looked at SimpleXML?

For example:

$string = "
 <root>
  <item>test1</item>
  <item>test2</item>
 </root>
";

$xml = simplexml_load_string($string);
seengee
This won't give him what he's asking for. That said, I'm not sure whether what he's asking for is a good idea
Pekka
@Pekka - yep i know but he wants an elegant solution for parsing XML and simpleXML is just that (imo). Too much margin for error otherwise
seengee
This are the first steps , I agree..but the rest?
+2  A: 

There are some nice code examples in the comments of SimpleXml manual page. I am sure you can make something work from objectsIntoArray() sample.

renick
+4  A: 

Ok, like already mentioned in the comments to your question I am not convinced this is really what you should be doing, but since I cant stand SimpleXml and dont want people to think it's the only way, here is how to do it

with DOM:

$arrXml = array();
$dom    = new DOMDocument;
$dom->loadXML( $xml );
foreach( $dom->getElementsByTagName( 'item' ) as $item ) {
    $arrXml[] = $dom->saveXML( $item );
}
print_r( $arrXml );

with XMLReader:

$arrXml = array();
$reader = new XmlReader;
$reader->xml( $xml );
while( $reader->read() ) {
    if( $reader->localName === 'item' && $reader->nodeType === 1 ) {
        $arrXml[] = $reader->readOuterXml();
    }
}
print_r( $arrXml );

and XMLParser*:

xml_parse_into_struct(xml_parser_create(), $xml, $nodes);
$xmlArr = array();
foreach($nodes as $node) {
    if($node['tag'] === 'ITEM') {
        $arrXml[] = "<item>{$node['value']}</item>";
    }
}
print_r($arrXml);

* this can also be done via callbacks triggered when an ITEM element is encountered. Would take more code, but is pretty flexible.

Note that all of the above might need some tweaking depending on your real XML.


Given that the XML in your question (which is likely only an example) is dirt simple and well defined, you can also use explode():

$arrXml = array_map( 'trim',
    array_filter(
        explode( PHP_EOL, $xml ),
        function( $line ) { return substr( $line, 0, 6 ) === '<item>'; }
));
print_r( $arrXml );

or a Regex (read disclaimer below)

preg_match_all('#<item>.*</item>#', $xml, $arrXml);
print_r($arrXml[0]);

Disclaimer Now, just to make sure you are not starting to parse XML with Regex or Explode on a regular basis: The last two approaches are only feasible if your markup is really that clearly defined as you show it. Otherwise parsing XML with Regex is not an option, because Regex cannot parse XML. That's a mathematical fact.

Gordon