PHP XML to array and back to XML - php

Here's the problem:
I have a given XML structure, similar to this one:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<programs>
<program>data_one</program>
<program>data_two</program>
<program>data_three</program>
</programs>
<periods>
<period date="2015-10-31T00:00:00+08:00">
<data_one>12.33</data_one>
<data_two>5.11</data_two>
<data_three>1544.22</data_three>
</period>
<period date="2015-12-31T00:00:00+08:00">
<data_one>19.33</data_one>
<data_two>123.44</data_two>
<data_three>999.12</data_three>
</period>
<period date="2015-11-30T00:00:00+08:00">
<data_one>1.01</data_one>
<data_two>19.23</data_two>
<data_three>234.11</data_three>
</period>
<period date="2016-01-31T00:00:00+08:00">
<data_one>69.33</data_one>
<data_two>80.12</data_two>
<data_three>65.87</data_three>
</period>
</periods>
</root>
I then used this little trick to convert part of the XML to an array (thanks to the answers I found here):
// convert periods from XML to array
$data = simplexml_load_string($this->xml->periods->asXML(), null, LIBXML_NOCDATA);
$json = json_encode($data);
$xml_as_array = json_decode($json, true);
That was done, because I needed to sort the the 'period' by date. This was quit simple done like this:
// create the sort-keys
foreach ($xml_as_array['period'] as $key => $row) {
$dates[$key] = $row['#attributes']['date'];
}
// sort by date
array_multisort($dates, SORT_ASC, $xml_as_array['period']);
A check with var_dump() shows, that the array is correctly sorted:
array(1) {
["period"]=>
array(4) {
[0]=>
array(4) {
["#attributes"]=>
array(1) {
["date"]=>
string(25) "2015-10-31T00:00:00+08:00"
}
["data_one"]=>
string(5) "12.33"
["data_two"]=>
string(4) "5.11"
["data_three"]=>
string(7) "1544.22"
}
[1]=>
array(4) {
["#attributes"]=>
array(1) {
["date"]=>
string(25) "2015-11-30T00:00:00+08:00"
}
["data_one"]=>
string(4) "1.01"
["data_two"]=>
string(5) "19.23"
["data_three"]=>
string(6) "234.11"
}
[2]=>
array(4) {
["#attributes"]=>
array(1) {
["date"]=>
string(25) "2015-12-31T00:00:00+08:00"
}
["data_one"]=>
string(5) "19.33"
["data_two"]=>
string(6) "123.44"
["data_three"]=>
string(6) "999.12"
}
[3]=>
array(4) {
["#attributes"]=>
array(1) {
["date"]=>
string(25) "2016-01-31T00:00:00+08:00"
}
["data_one"]=>
string(5) "69.33"
["data_two"]=>
string(5) "80.12"
["data_three"]=>
string(5) "65.87"
}
}
}
Now we come to the real problem: converting the array back to an XML structure similar as the original one (and as a bonus to replace the original '' with it).
I tried the usual recursive approach, but badly failed on creating the '' nodes with the 'date' attribute. There are some related questions here on stackoverflow addressing the array to xml conversion issue, but none of them worked...(therefor I'm not going to post them. Maybe its easier to come up with something fresh instead of trying to make my really bad code somehow to work ;-)
For any solutions, ideas or tipps I'd be very thankful.
Cheers,
hopfi2k

Consider using XSLT which you could bypass the PHP array sort altogether. As information, XSLT is a special-purpose declarative language (same type as SQL, sadly not as popular) used primarily to restructure/re-format/re-design XML files which your sort is exactly a native need as xslt maintains the <xslt:sort> method. Also, PHP like other general purpose languages (C#, Java, Python) maintains an XSLT 1.0 processor and so can run the transform to even overwrite the original XML file:
XSLT Script (save .xsl or .xslt file)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Sort periods by individual period's date attribute -->
<xsl:template match="periods">
<xsl:copy>
<xsl:apply-templates select="period">
<xsl:sort select="#date" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:transform>
PHP Script
// LOAD FILES
$doc = new DOMDocument();
$doc->load('Input.xml');
$xsl = new DOMDocument;
$xsl->load('XSLTfile.xsl');
// CONFIGURE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// TRANSFORM XML SOURCE
$newXml = $proc->transformToXML($doc);
// SAVE OUTPUT TO FILE
$xmlfile ='Output.xml'; // USE SAME NAME TO OVERWRITE ORIGINAL
file_put_contents($xmlfile, $newXml);
Output
<?xml version="1.0" encoding="UTF-8"?>
<root>
<programs>
<program>data_one</program>
<program>data_two</program>
<program>data_three</program>
</programs>
<periods>
<period date="2015-10-31T00:00:00+08:00">
<data_one>12.33</data_one>
<data_two>5.11</data_two>
<data_three>1544.22</data_three>
</period>
<period date="2015-11-30T00:00:00+08:00">
<data_one>1.01</data_one>
<data_two>19.23</data_two>
<data_three>234.11</data_three>
</period>
<period date="2015-12-31T00:00:00+08:00">
<data_one>19.33</data_one>
<data_two>123.44</data_two>
<data_three>999.12</data_three>
</period>
<period date="2016-01-31T00:00:00+08:00">
<data_one>69.33</data_one>
<data_two>80.12</data_two>
<data_three>65.87</data_three>
</period>
</periods>
</root>

Related

Unable to get node from simplexml_load_string

I understand this question has been asked, but all solutions I've found have not worked for me.
Given this:
SimpleXMLElement Object
(
[0] =>
<test>
<blah>
<x>
filler
</x>
</blah>
</test>
)
How do I get the <x> value?
I've tried
$doc = simplexml_load_string($xml_response);
print_r($doc->test->blah->x);
print_r($doc[0]->test->blah->x);
print_r($doc->{'0'}->test->blah->x);
print_r((string)$doc->{'0'}->test->blah->x);
print_r((string)$doc[0]->test->blah->x);
print_r((string)$doc->test->blah->x);
Here's the raw xml:
1.0" encoding="UTF-8" ?>
<xxx>
<test>
<blah>
<x>fillertexthere</x>
</blah>
<fillertexthere</Reason>
</test>
</xxx>%
Your SimpleXMLElement contains one string. I think that is because your xml contains < and >.
What you could do is first use htmlspecialchars_decode and then load your string.
(I have removed this line <fillertexthere</Reason> and % from your raw xml)
$xml_response = <<<DATA
<?xml version="1.0" encoding="UTF-8" ?>
<xxx>
<test>
<blah>
<x>fillertexthere</x>
</blah>
</test>
</xxx>
DATA;
$xml_response = htmlspecialchars_decode($xml_response);
var_dump($xml_response);
This will look like:
object(SimpleXMLElement)#1 (1) {
["test"]=>
object(SimpleXMLElement)#2 (1) {
["blah"]=>
object(SimpleXMLElement)#3 (1) {
["x"]=>
string(14) "fillertexthere"
}
}
}
You can echo the value of x like this:
echo $doc->test->blah->x;

Find where an xml element occurs in relation to other elements using PHP

I am using PHP's simpleXml to display a musicxml file as a musical score on the screen. Everything is working well unless there is a clef change somewhere in the score. Here is an excerpt of the xml file showing a clef change in measure 27:
<measure number="27">
<note>
</note>
<note>
</note>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note>
</note>
<note>
</note>
<note>
</note>
</measure>
I am going through the notes in each measure via foreach ($measure->note as $note). I can detect a clef change in a measure via if(isset($measure->attributes->clef)) but this doesn't tell me where the clef change occurs (after the second note of the measure and before the last three notes, in this example.)
I looked into simpleXmlIterator, but it doesn't seem to handle an excerpt out of an simpleXml object ($measure in this case.) I tried:
$sxi = new SimpleXMLIterator($measure);
This gave me the following warning:
Warning:
SimpleXMLElement::__construct(): Entity: line 29: parser error : Start
tag expected, '<' not found
When I var_dump($measure) I see that it places the clef change at the end of the notes array, but assigns it a number that could be used to determine its proper place in the sequence of notes:
object(SimpleXMLElement)#21 (4) {
["#attributes"]=>
array(2) {
["number"]=>
string(2) "25"
["width"]=>
string(6) "468.94"
}
["note"]=>
array(25) {
...
[20]=>
object(SimpleXMLElement)#43 (5) {
["rest"]=>
object(SimpleXMLElement)#49 (0) {
}
["duration"]=>
string(1) "4"
}
[21]=>
object(SimpleXMLElement)#45 (7) {
["#attributes"]=>
array(2) {
["default-x"]=>
string(6) "293.75"
["default-y"]=>
string(7) "-255.00"
}
["pitch"]=>
object(SimpleXMLElement)#49 (2) {
["step"]=>
string(1) "D"
["octave"]=>
string(1) "4"
}
["duration"]=>
string(1) "2"
}
}
["attributes"]=>
object(SimpleXMLElement)#44 (1) {
["clef"]=>
object(SimpleXMLElement)#49 (3) {
["#attributes"]=>
array(1) {
["number"]=>
string(1) "2"
}
["sign"]=>
string(1) "G"
["line"]=>
string(1) "2"
}
}
}
Object #44 (the clef change) should come between the two notes [actually, a rest and a note] that are objects #43 and #45. So, if I could figure out a way to access those "object numbers" my problem could be solved. Does anyone know how to do this, or a better way to resolve this issue?
Alternatively, run XPath directly with PHP's SimpleXMLElement::xpath using preceding-sibling::* and following-sibling::*. Below creates a multidimensional array, $clefs, indexed by measure number with two inner arrays for before_notes and after_notes:
Sample XML
$xml = simplexml_load_string(
'<score-partwise version="1.0">
<part-list>
<score-part id="P1">
<part-name>Voice</part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="26">
<note/>
<note/>
<note/>
<note/>
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
</measure>
<measure number="27">
<note/>
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note/>
<note/>
<note/>
</measure>
<measure number="28">
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note/>
<note/>
<note/>
<note/>
</measure>
<measure number="29">
<note/>
<note/>
<note/>
<note/>
<attributes>
<test>XSLT is cool!</test>
</attributes>
<note/>
</measure>
</part>
</score-partwise>');
Parsing Code
$clefs = [];
foreach($xml->xpath('//measure') as $item) {
$measure_num = (integer)$item->xpath('#number')[0];
$clefs['before_notes'][$measure_num] = count($item->xpath("attributes[clef!='']/preceding-sibling::note"));
$clefs['after_notes'][$measure_num] = count($item->xpath("attributes[clef!='']/following-sibling::note"));
}
echo var_dump($clefs);
// array(2) {
// ["before_notes"]=> array(4) {
// [26]=> int(5) [27]=> int(2) [28]=> int(1) [29]=> int(0)
// }
// ["after_notes"]=> array(4) {
// [26]=> int(0) [27]=> int(3) [28]=> int(4) [29]=> int(0)
// }
// }
I found a solution that worked for me. I realized that the return value of simpleXml() is an object (not an XML string.) So I can't feed a portion of it into simpleXmlIterator() and expect anything but errors.
Instead, I ended up treating $measure properly: as an object, and iterated through it as follows:
if(isset($measure->attributes->clef) && $measureNbr > 0) {
// There is a clef change in this measure!
$clefNbr = $measure->attributes->clef->attributes()->number;
$durationBeforeClefChg=0;
foreach($measure as $property => $value) {
// Count the unchorded durations before the clef change.
if(is_object($value) || is_array($value)) {
foreach($value as $p2 => $v2) {
if(trim($p2) == 'duration'
&& $property == 'note'
&& ((!property_exists($value,'staff'))
|| trim($value->staff) == $clefNbr)
&& !property_exists($value,'chord')) {
$durationBeforeClefChg+= intval(trim($v2));
}
if(trim($p2) == 'clef' && $property == 'attributes') {
$newClef = trim($v2->sign);
break 2;
}
}
}
}
}
Consider an XSLT solution. This special-purpose XML transformation language can run the preceding-sibling::* and following-sibling::* XPath methods to retrieve count of <notes> elements before and after <attributes> in a new, separate XML file.
PHP can run XSLT 1.0 scripts with its php-xsl class. Below demonstrates with sample XML rendering an output of specific information. With this approach, no nested foreach looping with if logic is needed.
Input XML (different measure numbers with attributes in various positions and one with no clef)
<?xml version="1.0"?>
<score-partwise version="1.0">
<part-list>
<score-part id="P1">
<part-name>Voice</part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="26">
<note/>
<note/>
<note/>
<note/>
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
</measure>
<measure number="27">
<note/>
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note/>
<note/>
<note/>
</measure>
<measure number="28">
<note/>
<attributes>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note/>
<note/>
<note/>
<note/>
</measure>
<measure number="29">
<note/>
<note/>
<note/>
<note/>
<attributes>
<test>XSLT is cool!</test>
</attributes>
<note/>
</measure>
</part>
</score-partwise>
XSLT (save as .xsl to be parsed in PHP below either by file or string)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="measure">
<xsl:copy>
<xsl:copy-of select="#*"/>
<notes_before_clef><xsl:copy-of select="count(attributes[clef!='']/preceding-sibling::note)"/></notes_before_clef>
<notes_after_clef><xsl:copy-of select="count(attributes[clef!='']/following-sibling::note)"/></notes_after_clef>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
PHP (enable php-xsl extension in .ini file)
// LOAD XML AND XSLT
$xml = new DOMDocument;
$xml->load('Input.xml'); // OR $xml->loadXML($xmlstring);
$xsl = new DOMDocument;
$xsl->load('XSLT_Script.xsl'); // OR $xsl->loadXML($xslstring);
// INITIALIZE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
// TRANSFORM SOURCE TO NEW TREE
$newXML = $proc->transformToXML($xml);
// ECHO OUTPUT
echo $newXML;
// SAVE OUTPUT TO FILE
file_put_contents('Output.xml', $newXML);
Output XML (parse this file for end use needs)
<?xml version="1.0"?>
<score-partwise version="1.0">
<part-list>
<score-part id="P1">
<part-name>Voice</part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="26">
<notes_before_clef>5</notes_before_clef>
<notes_after_clef>0</notes_after_clef>
</measure>
<measure number="27">
<notes_before_clef>2</notes_before_clef>
<notes_after_clef>3</notes_after_clef>
</measure>
<measure number="28">
<notes_before_clef>1</notes_before_clef>
<notes_after_clef>4</notes_after_clef>
</measure>
<measure number="29">
<notes_before_clef>0</notes_before_clef>
<notes_after_clef>0</notes_after_clef>
</measure>
</part>
</score-partwise>

Extract Data off multiple XML row

I have a really weird XML response and i need to extract it's data. I need to get the data in the "value" attribute but i need to choose them according to their "key" attributes.
This is how it looks like
<phone>
2125556666
</phone>
<State>
ny
</State>
<Response>
<data key="Supported" value="Yes"/>
<data key="Host" value="Remote"/>
<data key="WholeProductList">
<data key="Product" value="a-z44"/>
<data key="Product" value="c-k99"/>
<data key="Product" value="e-b089"/>
<data key="Product" value="z-p00"/>
<data key="Product" value="r-333"/>
<data key="Product" value="t-RS232"/>
<data key="Product" value="4-lve"/>
<data key="Product" value="Shutdown"/>
</data>
</Response>
In PHP i currenty have
$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;
echo $phone;
echo $state;
This currently outputs both phone number and state. It works fine.
Now i need to know if the "Supported" key's value is Yes or No, and if it's Yes, i need to get all "Products". I'm kinda stuck because i am having a hard time making the foreach statement and then checking the "key" attribute value.
Thanks!
Your XML is invalid. An XML document always needs a single document element node.
Example:
<root>
<phone>2125556666</phone>
<State>ny</State>
<Response>
<data key="Supported" value="Yes"/>
...
</data>
</Response>
</root>
The easiest way to fetch data from a DOM is XPath. In PHP that is provided by the DOMXPath class and part of the ext/dom. DOMXPath::evaluate() allows you to fetch node lists or scalar values from the DOM document.
$dom = new DOMDocument;
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$phone = $xpath->evaluate('string(/*/phone)');
$state = $xpath->evaluate('string(/*/State)');
var_dump($phone, $state);
Output:
string(10) "2125556666"
string(2) "ny"
An expression like /*/phone selects all phone element child nodes inside the document element. string(/*/phone) casts the first found node into a string and return that. If no node was found, it will return an empty string.
The XPath expression for the supported status is slightly more complex. Conditions for nodes are provided in []. It is possible to compare the result directly in XPath. The return value will be an boolean.
$supported = $xpath->evaluate('/*/Response/data[#key="Supported"]/#value = "Yes"');
var_dump($supported);
Output:
bool(true)
If the expression returns a node list you can iterate it with foreach().
$nodes = $xpath->evaluate(
'/*/Response/data[#key="WholeProductList"]/data[#key="Product"]/#value'
);
$products = [];
foreach ($nodes as $attributeNode) {
$products[] = $attributeNode->value;
}
var_dump($products);
Output:
array(8) {
[0]=>
string(5) "a-z44"
[1]=>
string(5) "c-k99"
[2]=>
string(6) "e-b089"
[3]=>
string(5) "z-p00"
[4]=>
string(5) "r-333"
[5]=>
string(7) "t-RS232"
[6]=>
string(5) "4-lve"
[7]=>
string(8) "Shutdown"
}
This won't quite work "as is" since I don't know what the actual structure of the XML document is, but in short you map the XML nodes to XPath like //root/node/child_node/#attribute and so on.
It should also have some sanity (not null) type checking in.
$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$xQuery = new DOMXPath($xmltmp);
//not sure what your root node is so the query path is probably wrong
$supported = $xQuery->query('/Response/data[#key="Supported"]/#value')->value;
You can also replace:
$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;
With something like (again - without the full structure of the XML document the path itself is probably not quite right):
$phone = $xQuery->query('/phone')->item(0)->nodeValue;
$state = $xQuery->query('/State')->item(0)->nodeValue;

Using PHP to manage GMail Mail Filter XML Files

Since GMail made it possible to import and export the mail filters, I'd like to manage the XML files that are exported from GMail using a PHP script, as there are some known issues with the number of characters in the search filters.
I've found the simplexml_load_file function in PHP, and have performed var_dump() against the performed export, but I now don't seem to be able to access the apps namespace within the generated XML file.
Following various pages within the PHP manual, I created this very simple script to read the XML out so I can start to process out the filters I've already created. Unfortunately, it seems to be missing the key parts!
<pre><?php
if(file_exists("mailfilters.xml")) {
$xml = simplexml_load_file("mailfilters.xml");
$namespaces = $xml->getNamespaces(true);
foreach ($namespaces as $prefix => $ns) {
$xml->registerXPathNamespace($prefix, $ns);
}
var_dump($xml);
} else {
die("Failed to open filter file");
}
?></pre>
This returns this data (extract)
["entry"]=>
array(268) {
[0]=>
object(SimpleXMLElement)#3 (5) {
["category"]=>
object(SimpleXMLElement)#271 (1) {
["#attributes"]=>
array(1) {
["term"]=>
string(6) "filter"
}
}
["title"]=>
string(11) "Mail Filter"
["id"]=>
string(45) "tag:mail.google.com,2008:filter:1284991916868"
["updated"]=>
string(20) "2010-10-28T11:59:31Z"
["content"]=>
object(SimpleXMLElement)#272 (0) {
}
}
[1]=>
object(SimpleXMLElement)#4 (5) {
["category"]=>
object(SimpleXMLElement)#272 (1) {
["#attributes"]=>
array(1) {
["term"]=>
string(6) "filter"
}
}
["title"]=>
string(11) "Mail Filter"
["id"]=>
string(45) "tag:mail.google.com,2008:filter:1284991925003"
["updated"]=>
string(20) "2010-10-28T11:59:31Z"
["content"]=>
object(SimpleXMLElement)#271 (0) {
}
}
Here's an extract from the XML file I have downloaded today, used to create the above output:
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'>
<title>Mail Filters</title>
<id>tag:mail.google.com,2008:filters:1284991916868,...,1287734777820</id>
<updated>2010-10-28T11:59:31Z</updated>
<author>
<name>My Name</name>
<email>my#email.addr.es</email>
</author>
<entry>
<category term='filter'></category>
<title>Mail Filter</title>
<id>tag:mail.google.com,2008:filter:1284991916868</id>
<updated>2010-10-28T11:59:31Z</updated>
<content></content>
<apps:property name='from' value='an#email.addr.es'/>
<apps:property name='shouldArchive' value='true'/>
<apps:property name='shouldTrash' value='true'/>
</entry>
<entry>
<category term='filter'></category>
<title>Mail Filter</title>
<id>tag:mail.google.com,2008:filter:1284993579743</id>
<updated>2010-10-28T11:59:31Z</updated>
<content></content>
<apps:property name='subject' value='Some Relevant Subject'/>
<apps:property name='label' value='MyCoolLabel'/>
<apps:property name='shouldArchive' value='true'/>
</entry>
Other "apps:property" verbs include:
<apps:property name='hasTheWord' value=''/>
<apps:property name='shouldAlwaysMarkAsImportant' value=''/>
<apps:property name='doesNotHaveTheWord' value=''/>
I recently had a similar "problem". I was trying to get the email signature settings from Google Apps. This is what the XML Response from Google looks like:
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'>
<id>https://apps-apis.google.com/a/feeds/emailsettings/2.0/domain.com/user/signature</id>
<updated>2012-08-31T15:22:03.067Z</updated>
<link rel='self' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/emailsettings/2.0/domain.com/user/signature?xoauth_requestor_id=user#domain.com'/>
<link rel='edit' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/emailsettings/2.0/domain.com/user/signature?xoauth_requestor_id=user#domain.com'/>
<apps:property name='signature' value='Here goes the email signature...'/>
</entry>
I was not able the get the attributes out of apps:property using the SimpleXMLElement. This is how i finally solved it:
// create SimpleXMLElement with XML input as string
$xml = new SimpleXMLElement($feed);
// get namespace from XML
$namespaces = $xml->getNamespaces(true);
// get children (using namespace) and attributes
$appsProperty = $xml->children($namespaces['apps'])->attributes();
// attributes are now stored in array $appsProperty and can be accessed
echo "Name: ".$appsProperty['name'];
echo "Signature: ".$appsProperty['value'];
Jon,
Full marks for linking this from Facebook, I'd never have seen it otherwise and I was doing EXACTLY this yesterday, for a google service!! I think using XPath is a bit of a red herring, let me show you how to access the elements and hopefully it will give you enough information for what you want to do.
You're on the right tracks with $xml->getNamespaces() - but don't iterate there, you need to use the namespace you want on the parent element you want. Firstly, you need to work only on the entry elements, since these are the majority, you might as well loop and check if you have the right one:
foreach($xml as $tag) {
if($tag->getName() == "entry") {
// awesome, do Cool Stuff (TM) here
}
}
Now, you have the element in the $tag variable, and you want the apps: namespaced child elements. So do this:
$tag->getChildren($namespaces['apps']);
When you iterate over that collection, you will see the info you wanted.
HTH,
Lorna

Need to extract values from a XML file

I have a XML file, and the layout is such
<author>
<name></name>
<iso></iso>
<price></price>
</author>
I know how it loops. I want to know how I can extract the value of
<name>
Thanks
Jean
[edit]
my apologies, if in the
<author>
<name>
<first_name></first_name>
<last_name></lastname>
</name>
</author>
I want to extract first_name
Use simplexml or similar:
<?php
$string = <<<XML
<author>
<name>
<first_name>John</first_name>
<last_name>Smith</last_name>
</name>
</author>
XML;
$xml = simplexml_load_string($string);
var_dump($xml);
?>
Will output something like this:
object(SimpleXMLElement)#1 (1) {
["name"]=>
object(SimpleXMLElement)#2 (2) {
["first_name"]=>
string(4) "John"
["last_name"]=>
string(5) "Smith"
}
}
And you can access the name like this:
echo $xml->name->first_name; // outputs 'John'
echo $xml->name->last_name; // outputs 'Smith'
Use SimpleXML.
Edit: I see. That wasn't showing up before. Try this:
$xml = simple_xml_load_string([your XML string])
echo $xml->name;
Does that work?

Categories