I'm trying to combine multiple XML files, using SimpleXML if possible. I'm just trying to append products, children, and child data from file 2 into file 1. I'm not trying to merge elements, just append file 2 to the bottom of file 1, and so on. (Though I guess this is technically merging merchandiser elements?) The files contain the same schema and will both look similar to the example below, only thing that will be changing is the actual text. This is just XML for two different products, I added a large space in between products so that it's easier to see where it ends.
<merchandiser xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="merchandiser.xsd">
<header>
<merchantId>35928</merchantId>
<merchantName>Sunspel Clothing</merchantName>
<createdOn>01/14/2016 02:03:31</createdOn>
</header>
<product product_id="14633" name="Cotton Socks" sku_number="1588/102">
<category>
<primary>Accessories</primary>
<secondary>Men's~~Socks</secondary>
</category>
<URL>
<product>
http://click.linksynergy.com/link?id=D*rqD2paIXY&offerid=191965.14633&type=15&murl=http%3A%2F%2Fwww.sunspel.com%2Fuk%2Fcotton-sock-black.html
</product>
<productImage>
http://www.sunspel.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/1/5/1588-102-new.jpg
</productImage>
</URL>
<description>
<short>
Our new cotton socks are designed by Sunspel and crafted in an Italian factory steeped in years of experience, skill and heritage. They are made from the highest quality, extra-long staple Egyptian cotton yarn which, prior to knitting is combed, twisted and mercerised to enhance the comfort, shine and absorption of the fabric as well as its resistance to pilling and shrinking.
</short>
</description>
<discount currency="GBP">
<type>amount</type>
</discount>
<price currency="GBP">
<retail>15.00</retail>
</price>
<shipping>
<availability>in-stock</availability>
</shipping>
<pixel>
http://ad.linksynergy.com/fs-bin/show?id=D*rqD2paIXY&bids=191965.14633&type=15&subid=0
</pixel>
</product>
<product product_id="15115" name="Cotton Socks" sku_number="1589/236">
<category>
<primary>Accessories</primary>
<secondary>Men's~~Socks~~Men's</secondary>
</category>
<URL>
<product>
http://click.linksynergy.com/link?id=D*rqD2paIXY&offerid=191965.15115&type=15&murl=http%3A%2F%2Fwww.sunspel.com%2Fuk%2Fmens-cotton-socks-navy-stripes.html
</product>
<productImage>
http://www.sunspel.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/1/5/1588-236-new.jpg
</productImage>
</URL>
<description>
<short>
Our new cotton socks are designed by Sunspel and crafted in an Italian factory steeped in years of experience, skill and heritage. They are made from the highest quality, extra-long staple Egyptian cotton yarn which, prior to knitting is combed, twisted and mercerised to enhance the comfort, shine and absorption of the fabric as well as its resistance to pilling and shrinking.
</short>
</description>
<discount currency="GBP">
<type>amount</type>
</discount>
<price currency="GBP">
<retail>17.00</retail>
</price>
<shipping>
<availability>in-stock</availability>
</shipping>
<pixel>
http://ad.linksynergy.com/fs-bin/show?id=D*rqD2paIXY&bids=191965.15115&type=15&subid=0
</pixel>
</product>
<product product_id="15116" name="Cotton Socks" sku_number="1589/711">
<category>
<primary>Accessories</primary>
<secondary>Men's~~Socks~~Men's</secondary>
</category>
<URL>
<product>
http://click.linksynergy.com/link?id=D*rqD2paIXY&offerid=191965.15116&type=15&murl=http%3A%2F%2Fwww.sunspel.com%2Fuk%2Fmens-cotton-socks-charcoal-melange-stripes.html
</product>
<productImage>
http://www.sunspel.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/1/5/1588-711-new.jpg
</productImage>
</URL>
<description>
<short>
Our new cotton socks are designed by Sunspel and crafted in an Italian factory steeped in years of experience, skill and heritage. They are made from the highest quality, extra-long staple Egyptian cotton yarn which, prior to knitting is combed, twisted and mercerised to enhance the comfort, shine and absorption of the fabric as well as its resistance to pilling and shrinking.
</short>
</description>
<discount currency="GBP">
<type>amount</type>
</discount>
<price currency="GBP">
<retail>17.00</retail>
</price>
<shipping>
<availability>in-stock</availability>
</shipping>
<pixel>
http://ad.linksynergy.com/fs-bin/show?id=D*rqD2paIXY&bids=191965.15116&type=15&subid=0
</pixel>
</product>
With some foreach statements I'm able to append all product children and attributes, but this doesn't actually give me the child data.
$file1 = '35928_3210820_mp.xml';
$file2 = '39153_3210820_mp.xml';
$fileout = 'ukmerge.xml';
$xml1 = simplexml_load_file( $file1 );
$xml2 = simplexml_load_file( $file2 ); // loop through the product and add them and their attributes to xml1
$product = $xml2->product;
$prod = $xml2->merchandiser->header->product;
$category = $product->category;
$url = $product->URL;
$description = $product->description;
foreach( $xml2->children() as $child ) {
$new = $xml1->addChild( $child->getName() , htmlspecialchars($child) );
foreach( $child->attributes() as $key => $value ) {
$new->addAttribute( $key, $value );
}
} $fh = fopen( $fileout, 'w') or die ( "can't open file $fileout" );
fwrite( $fh, $xml1->asXML() );
fclose( $fh );
When I try to add on from there then everything gets messed up and nothing is in the correct place/order anymore. I'd also like to put this into a function since I'm going to be doing it often. Any help is greatly appreciate as I've been struggling with this for a few days now and have scowered over a few dozen stackoverflow and php.net threads.
One of the things that's confusing me is the <merchandiser> and <header> tags that every file starts with. Once the merchandiser tag ends it is the end of the document so I need to take only what's inside the merchandiser tag of file 2 and append it inside the merchandiser tag of file 1. The header tag just confuses me cause I'm not sure if it's gets in the way or not.
As preliminary note, your XML sample is malformed. Also it is not coherent with your code (i.e. there is not ->merchandiser->header->product ).
So, in this example I will use a different sample, like this one (file1.xml):
<root>
<product>
<name>Product 1</name>
</product>
<product>
<name>Product 2</name>
</product>
</root>
and this one (file2.xml):
<root>
<product>
<name>Product 3</name>
</product>
<product>
<name>Product 4</name>
</product>
</root>
You don't want to use DOMDocument->importNode() due “it kept throwing a lot of errors”.
You can use DOMDocument in conjunction with SimpleXML and dom_import_simplexml() function.
First of all, prepare destination XML: load the file with SimpleXML, create a DOMDocument using dom_import_simplexml() and set $parent variable to <root> element:
$dst = simplexml_load_file( 'file1.xml' );
$dst = dom_import_simplexml( $dst )->ownerDocument;
$parent = $dst->getElementsByTagName( 'root' )->item(0);
Then, load second file with SimpleXML:
$src = simplexml_load_file( 'file2.xml' );
Through a foreach() loop, import each <product> element from SimpleXML to DOMDocument and appent it as child of $parent node:
foreach( $src->product as $product )
{
$node = dom_import_simplexml( $product );
$node = $dst->importNode( $node, 1 );
$parent->appendChild( $node );
}
Now, your merged XML is ready. You can print it using $dst->saveXML().
I've not be able to product a correctly indented XML. BTW to do this, you can reload-it:
$final = new DOMDocument();
$final->loadXML( $dst->saveXML(), LIBXML_NOBLANKS );
$final->formatOutput = True;
echo $final->saveXML();
Final output:
<?xml version="1.0"?>
<root>
<product>
<name>Product 1</name>
</product>
<product>
<name>Product 2</name>
</product>
<product>
<name>Product 3</name>
</product>
<product>
<name>Product 4</name>
</product>
</root>
Related
I need to make some changes to the xml tags I use. I need to collect some of these tags in other tags.
For example:
<image> image_url </image>
the tags
<Images>
<Image> image_url <image>
</Images>
must be
I may also need to use some tags below or above the existing tag
For example:
<productname> pr_name </productname>
<newproductname> pr_name </newproductname>
Test xml output:
<Root>
<Products>
<Product>
<productname> pr_name </productname>
<price> pr_price </price>
<sku> pr_sku </sku>
<Image> image_url <image>
<Product>
</Products>
</Root>
I want it this way :)
<Root>
<Products>
<Product>
<newproductname> pr_name </newproductname>
<productname> pr_name </productname>
<price> pr_price </price>
<sku> pr_sku </sku>
<Images>
<Image> image_url <image>
</Images>
<newsku> pr_newsku </newsku>
<Product>
</Products>
</Root>
How do I make changes to this structure that I use like.
header('Content-Type: application/xml');
$xml = new DOMDocument();
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
$xml->load('test.xml');
$xml_string = $xml->saveXML();
echo $xml_string;
Given the sample XML below, which is based upon that cited in the question but expanded slightly and corrected the badly formed XML as seen above, you can easily achieve the desired structure with careful use of DOMXPath and insertBefore - with a little twist on the latter to actually perform insertAfter
$xml='<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Products>
<Product>
<productname> pr_name 1</productname>
<price> pr_price 1</price>
<sku> pr_sku 1</sku>
<Image> image_url 1.1</Image>
<Image> image_url 1.2</Image>
</Product>
<Product>
<productname> pr_name 2</productname>
<price> pr_price 2</price>
<sku> pr_sku 2</sku>
<Image> image_url 2</Image>
</Product>
<Product>
<productname> pr_name 3</productname>
<price> pr_price 3</price>
<sku> pr_sku 3</sku>
<Image> image_url 3.1</Image>
<Image> image_url 3.2</Image>
<Image> image_url 3.3</Image>
</Product>
<Product>
<productname> pr_name 4</productname>
<price> pr_price 4</price>
<sku> pr_sku 4</sku>
</Product>
</Products>
</Root>';
$dom=new DOMDocument('1.0','utf-8');
$dom->formatOutput=true;
$dom->validateOnParse=false;
$dom->recover=true;
$dom->strictErrorChecking=false;
$dom->preserveWhiteSpace=false;
$dom->loadXML( $xml );
$errors = libxml_get_errors();
libxml_clear_errors();
$xp=new DOMXPath( $dom );
$col=$xp->query( '//Products/Product' );
if( $col->length > 0 ){
foreach( $col as $node ){
/* Get the `productname` and create a new element before with same value */
$productname=$xp->query( 'productname', $node )->item(0);
$newproductname=$dom->createElement( 'newproductname', $productname->textContent );
$node->insertBefore( $newproductname, $productname );
/* Find all the Image tags within parent */
$ref=$xp->query( 'Image', $node );
/* determine reference node to use for `insertBefore` */
if( $ref && $ref->length > 0 )$refNode=$ref->item(0);
else $refNode=$node->lastChild;
/* create a new `Images` node */
$oImages=$dom->createElement('Images');
$node->insertBefore( $oImages, $refNode );
/* using previously discovered `Image` nodes, add to the new `Images` element */
foreach( $ref as $img )$oImages->appendChild( $img );
}
}
/* for demo display */
printf('<pre>%s</pre>',print_r( htmlentities( $dom->saveXML() ), true ) );
/* For real output */
#header( 'Content-Type: application/xml' );
#exit( $dom->saveXML() );
The output from the debug print ( printf above ) is as follow and follows, I believe, the desired output format - apart from new, unmentioned newsku tag which you show above:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Products>
<Product>
<newproductname> pr_name 1</newproductname>
<productname> pr_name 1</productname>
<price> pr_price 1</price>
<sku> pr_sku 1</sku>
<Images>
<Image> image_url 1.1</Image>
<Image> image_url 1.2</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 2</newproductname>
<productname> pr_name 2</productname>
<price> pr_price 2</price>
<sku> pr_sku 2</sku>
<Images>
<Image> image_url 2</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 3</newproductname>
<productname> pr_name 3</productname>
<price> pr_price 3</price>
<sku> pr_sku 3</sku>
<Images>
<Image> image_url 3.1</Image>
<Image> image_url 3.2</Image>
<Image> image_url 3.3</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 4</newproductname>
<productname> pr_name 4</productname>
<price> pr_price 4</price>
<Images/>
<sku> pr_sku 4</sku>
</Product>
</Products>
</Root>
I have a feed with products, all the products have a child node called 'category' with a value. I can't find a way to return all products with a certain category value.
The XML looks something like this
<product>
<name>xxxx</name>
<category>Category A</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
<product>
<name>xxxx</name>
<category>Category A</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
I've tried looping through the XML, using PHP code like this:
$xml = simplexml_load_file('file.xml');
foreach ($xml as $product) {
if ((string) $product['category'] == 'Category A') {
echo (string) $product['name'];
}
}
Expected outcome is to return/echo other child nodes for that product. What would be the best approach for this?
Your approach seems sound, I'm not familiar enough with SimpleXML to say why it's not working. But, since you asked for the best approach, I'm partial to DomDocument and XPath myself:
$xml = <<< XML
<?xml version="1.0"?>
<products>
<product>
<name>xxxx</name>
<category>Category A</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
<product>
<name>xxxx</name>
<category>Category A</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
<product>
<name>xxxx</name>
<category>Category B</category>
</product>
</products>
XML;
$dom = new DomDocument;
$dom->loadXML($xml);
$xpath = new DomXPath($dom);
$search = "Category A";
$nodes = $xpath->query("//product[category='$search']/name");
foreach ($nodes as $node) {
printf("%s\n", $node->textContent);
}
For SimpleXML, after a little digging it looks like it needs to access elements with object notation, not array notation. This worked for me:
$x = simplexml_load_string($xml);
foreach ($x->product as $product) {
if ((string) $product->category == 'Category A') {
echo (string) $product->name;
}
}
But I maintain that learning DOM and XPath methods will serve you better in the long run; they're both well established standards that are used in many languages. Knowledge about SimpleXML is not something you can transfer to another environment.
I am having nested XML, I want to remove only parent node < items> in xml document keeping all its child nodes.
<root>
<items>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
</items>
</root>
Expected Output -
<root>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
</root>
I have researched & tried a lot, on removing the < items> node all its child nodes are also getting deleted. Please help if there is any way using DOMDocument or any other way in php.
Well, Geza Boems answer is not exactly what I meant. Using Xpath you can fetch the items nodes for iteration. This is a stable result, so you can iterate it while modifying the DOM.
$document = new DOMDocument();
$document->loadXML($input);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//items') as $itemsNode) {
// as long that here is any child inside it
while ($itemsNode->firstChild instanceof DOMNode) {
// move it before its parent
$itemsNode->parentNode->insertBefore($itemsNode->firstChild, $itemsNode);
}
// remove the empty items node
$itemsNode->parentNode->removeChild($itemsNode);
}
echo $document->saveXML();
As #ThW mentioned, you have to collect the child nodes in ITEMS, then insert them into ROOT, and finally delete ITEMS.
$input = "
<root>
<items>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
<Product>
<name> </name>
<size> </size>
<images>
<img1></img1>
<img2></img2>
</images>
</Product>
</items>
</root>";
$doc = new DOMDocument();
$ret = $doc->loadXML($input);
$root = $doc->firstChild;
$nodes_to_insert = array();
$nodes_to_remove = array();
foreach($root->childNodes as $items) {
if($items->nodeName != "items") {
continue;
}
$nodes_to_remove[] = $items;
foreach($items->childNodes as $child) {
if($child->nodeType != XML_ELEMENT_NODE) {
continue;
}
$nodes_to_insert[] = $child;
}
}
foreach($nodes_to_insert as $node) {
$root->appendChild($node);
}
foreach($nodes_to_remove as $node) {
$root->removeChild($node);
}
var_dump($doc->saveXML());
This code will search for all "items" tag within root, not only one. Inside "items", it will search all normal node (ELEMENT type, but no TEXT node, etc.)
In the last line there is a dump, but normally you will not see anything in a browser, because of the XML header line. But if you take a look at page source, the result will be shown.
PS: it is quite important to not modify xml structure when you walk it. That's why i do only collection first, then the insert and delete actions.
foreach($resultXML->products->children() as $product) {
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Suppose I wanted to screen out the ones that had the same title, and only display the first title that appears in the return results.
I'm not working with my own database, this is all about what's displayed.
I suppose the easiest way would be to keep track of the titles in an array, and checking it each iteration.
$titles = array();
foreach($resultXML->products->children() as $product) {
if (in_array($product->title, $titles) continue;
$titles[] = $product->title;
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Assuming that the title is contained in $product->title. You could do something fancier through array functions, but I don't see a reason to make a simple problem complicated.
You have not provided any exemplary XML, so given for
<?xml version="1.0" encoding="UTF-8"?>
<example>
<products>
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Second Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
</products>
</example>
You want to get all product elements with an advertiser-name that is not an advertiser-name of all preceding product elements.
So for the XML above, that would be the 1st and 3rd product element.
You can write that down as an XPath expression:
/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]
And as PHP code:
$xml = simplexml_load_string($buffer);
$expr = '/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]';
foreach ($xml->xpath($expr) as $product) {
echo $product->asXML(), "\n";
}
This produces the following output:
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
So one answer to your question therefore is: Only query those elements from the document you're interested in. XPath can be used for that with SimpleXMLElement.
Related questions:
Implementing condition in XPath
I've been tearing my hair out with this now for a few hours and thought I'd post it up here to see if anybody had any suggestions.
Basically I am receving some XML date via SOAP/Curl call which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<LocationAvailabilityResponse xmlns="">
<getAvailabilityReturn>
<errors />
<requestID>389851</requestID>
<hotels>
<hotels>
<hotel>
<apt>false</apt>
<distance>0</distance>
<fromPrice>18.5</fromPrice>
<hotelName>Britannia Hotel Stockport</hotelName>
<id>5165</id>
<images>
<images>
<hasThumbnail>true</hasThumbnail>
<height>187</height>
<thumbnailHeight>50</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_swimming_pool_1_swi_5165.JPG</thumbnailURL>
<thumbnailWidth>68</thumbnailWidth>
<title>Britannia Hotel Stockport</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_swimming_pool_1_swi_5165.JPG</url>
<width>257</width>
</images>
<images>
<hasThumbnail>false</hasThumbnail>
<height>187</height>
<thumbnailHeight>0</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_swimming_pool_2_swi_5165.JPG</thumbnailURL>
<thumbnailWidth>0</thumbnailWidth>
<title>Swimming Pool</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_swimming_pool_2_swi_5165.JPG</url>
<width>257</width>
</images>
<images>
<hasThumbnail>false</hasThumbnail>
<height>187</height>
<thumbnailHeight>0</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_hotel_entrance_1_ent_5165.JPG</thumbnailURL>
<thumbnailWidth>0</thumbnailWidth>
<title>Hotel Entrance</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_hotel_entrance_1_ent_5165.JPG</url>
<width>257</width>
</images>
<images>
<hasThumbnail>false</hasThumbnail>
<height>187</height>
<thumbnailHeight>0</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_hotel_gym_1_gym_5165.JPG</thumbnailURL>
<thumbnailWidth>0</thumbnailWidth>
<title>Hotel Gym</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_hotel_gym_1_gym_5165.JPG</url>
<width>257</width>
</images>
<images>
<hasThumbnail>false</hasThumbnail>
<height>187</height>
<thumbnailHeight>0</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_hotel_lounge_1_lou_5165.JPG</thumbnailURL>
<thumbnailWidth>0</thumbnailWidth>
<title>Hotel Lounge</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_hotel_lounge_1_lou_5165.JPG</url>
<width>257</width>
</images>
<images>
<hasThumbnail>false</hasThumbnail>
<height>187</height>
<thumbnailHeight>0</thumbnailHeight>
<thumbnailURL>http://static.superbreak.net/content/images/Hotel/thumbs/britannia_hotel_stockport_four_poster_bedroom_1_pst_5165.JPG</thumbnailURL>
<thumbnailWidth>0</thumbnailWidth>
<title>Four Poster Bedroom</title>
<url>http://static.superbreak.net/content/images/Hotel/britannia_hotel_stockport_four_poster_bedroom_1_pst_5165.JPG</url>
<width>257</width>
</images>
</images>
<latitude>53.398941</latitude>
<location>Stockport</location>
<longitude>-2.13463</longitude>
<starRating>3</starRating>
</hotel>
<roomUnits>
<roomUnits>
<allocation>1</allocation>
<boardCode>RO</boardCode>
<boardDescription>Room only</boardDescription>
<maxOccupancy>2</maxOccupancy>
<minOccupancy>1</minOccupancy>
<price>18.5</price>
<stdOccupancy>2</stdOccupancy>
<unitDescription>Double For 1-2</unitDescription>
<unitID>162</unitID>
</roomUnits>
<roomUnits>
<allocation>1</allocation>
<boardCode>RO</boardCode>
<boardDescription>Room only</boardDescription>
<maxOccupancy>2</maxOccupancy>
<minOccupancy>1</minOccupancy>
<price>18.5</price>
<stdOccupancy>2</stdOccupancy>
<unitDescription>Twin For 1-2</unitDescription>
<unitID>161</unitID>
</roomUnits>
<roomUnits>
<allocation>1</allocation>
<boardCode>RO</boardCode>
<boardDescription>Room only</boardDescription>
<maxOccupancy>2</maxOccupancy>
<minOccupancy>2</minOccupancy>
<price>23.5</price>
<stdOccupancy>2</stdOccupancy>
<unitDescription>Executive Double Room</unitDescription>
<unitID>65</unitID>
</roomUnits>
<roomUnits>
<allocation>1</allocation>
<boardCode>RO</boardCode>
<boardDescription>Room only</boardDescription>
<maxOccupancy>2</maxOccupancy>
<minOccupancy>2</minOccupancy>
<price>23.5</price>
<stdOccupancy>2</stdOccupancy>
<unitDescription>Executive Twin Room</unitDescription>
<unitID>64</unitID>
</roomUnits>
</roomUnits>
</hotels>
I'm attempting to iterate through each hotels hotels result and turn each result into a multi dimensional array. The code I'm using which isn't working as I'd like is below:
$doc = new DOMDocument();
if ($doc->loadXML($result)) {
$items = $doc->getElementsByTagName('hotels');
$hotelnames = array();
foreach($items as $item) {
$hotelname = array();
$hotelimages = array();
if($item->childNodes->length) {
foreach($item->childNodes as $i) {
$hotelname[$i->nodeName] = $i->nodeValue;
if($i->childNodes->length){
foreach($i->childNodes as $z) {
if($z->childNodes->length){
foreach($z->childNodes as $x) {
$hotelimage[$x->nodeName] = $x->nodeValue;
}
}
}
}
$hotelimages[] = $hotelimage;
}
}
$hotelnames[] = $hotelname;
}
}
I'm guessing the issues I'm facing are mostly caused by the fact that the child and parent nodes are named the same for hotels and for the images.
Any help or a nod in the right direction will be much appreciated.
I suggest you using xpath (for example in SimpleXML implementation http://php.net/manual/en/simplexmlelement.xpath.php) for loading the values you need.
Or if you need whole XML parsed to array, you can always use PEAR XML_Serializer package (http://pear.php.net/package/XML_Serializer) to unserialize your XML.
Instead of working directly with the DOM I would recommend that you, unless you actually do need access to the DOM, perform these tasks using SimpleXML
It makes it very easy to work with XML data and you can act on it almost like a normal array.
Example
<?php
$url = 'http://www.flickr.com/services/feeds/photos_public.gne';
foreach(simplexml_load_file($url)->entry as $entry) {
echo $entry->content;
}
?>
Quite few lines for that functionality :)
Good luck!
I am looking in to the XML and I noticed some XML tags are not correct
Ex: <images><images></images><images></images></images> same is the case with roomunit.
I think it should be like <images><image></image><image></image></images> this will help to iterate over XML tag in php.