I need to get <name> and <URL> tag's value where subtype="mytype".How can do it in PHP?
I want document name and test.pdf path in my result.
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
Use SimpleXML and XPath, eg
$xml = simplexml_load_file('path/to/file.xml');
$items = $xml->xpath('//item[#subtype="mytype"]');
foreach ($items as $item) {
$name = (string) $item->name;
$url = (string) $item->url;
}
PHP 5.1.2+ has an extension called SimpleXML enabled by default. It's very useful for parsing well-formed XML like your example above.
First, create a SimpleXMLElement instance, passing the XML to its constructor. SimpleXML will parse the XML for you. (This is where I feel the elegance of SimpleXML lies - SimpleXMLElement is the entire library's sole class.)
$xml = new SimpleXMLElement($yourXml);
Now, you can easily traverse the XML as if it were any PHP object. Attributes are accessible as array values. Since you're looking for tags with specific attribute values, we can write a simple loop to go through the XML:
<?php
$yourXml = <<<END
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
END;
// Create the SimpleXMLElement
$xml = new SimpleXMLElement($yourXml);
// Store an array of results, matching names to URLs.
$results = array();
// Loop through all of the tests
foreach ($xml->required[0]->item as $item) {
if ( ! isset($item['subtype']) || $item['subtype'] != 'mytype') {
// Skip this one.
continue;
}
// Cast, because all of the stuff in the SimpleXMLElement is a SimpleXMLElement.
$results[(string)$item->name] = (string)$item->url;
}
print_r($results);
Tested to be correct in codepad.
Hope this helps!
You can use the XML Parser or SimpleXML.
Related
I load the following XML data into SimpleXML like this:
<?php
$xmlString = <<<'XML'
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1">
<title></title>
<field_a></field_a>
<field_b></field_b>
<field_d1></field_d1>
<field_d2></field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g></field_g>
<field_gewicht></field_gewicht>
<field_gtin></field_gtin>
<field_l></field_l>
<field_t></field_t>
<field_abdrueckmutter></field_abdrueckmutter>
<field_sicherung></field_sicherung>
<field_wellenmutter></field_wellenmutter>
</item>
</response>
XML;
$xml = simplexml_load_string($xml);
How can I achieve the following result:
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1"></item>
</response>
To delete all empty elements, I could use the following working code:
foreach ($xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement) {
unset($emptyElement[0]);
}
But that's not exactly what I want.
Basically, when the <title> element is empty, I want to remove it with all its siblings and keep the parent <item> element.
What's important: I also want to keep empty element, if the <title> is not empty. See <item key="0"> for example. The elements <field_e>, <field_g2> and <field_t>will be left untouched.
Is there an easy xpath query which can achieve that? Hope anyone can help. Thanks in advance!
This xpath query is working:
foreach ($xml->xpath('//title[not(text()[normalize-space()])]/following-sibling::*') as $emptyElement) {
unset($emptyElement[0]);
}
It keeps the <title> element but I can live with that.
DOM is more flexible manipulating nodes:
$document = new DOMDocument();
$document->loadXML($xmlString);
$xpath = new DOMXpath($document);
$expression = '/response/item[not(title[normalize-space()])]';
foreach ($xpath->evaluate($expression) as $emptyItem) {
// replace children with an empty text node
$emptyItem->textContent = '';
}
echo $document->saveXML();
The XML that's received is below. How can I get the values ('AI', '3', '20.78'...) and display them in PHP?
The values are always returned in that order but the length can vary.
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Item Type="AI" Chan="3" Value="20.78" Manual="OFF" Min="0.00" Max="100.00" Units="degC" Name="Workshop Temp" />
</Data>
Any ideas would be much appreciated!
You might find the documentation of SimpleXMLElement::attributes useful,
SimpleXMLElement::attributes — Identifies an element's attributes
Return Values
Returns a SimpleXMLElement object that can be iterated over to loop through the attributes on the tag.
Returns NULL if called on a SimpleXMLElement object that already represents an attribute and not a tag.
here is how you should use it:
$str = <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Item Type="AI" Chan="3" Value="20.78" Manual="OFF" Min="0.00" Max="100.00" Units="degC" Name="Workshop Temp" />
</Data>
XML;
$xml = simplexml_load_string($str);
foreach($xml->Item[0]->attributes() as $key => $att) {
echo $att."\n";
}
Here is the XML that I am working on :
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:noo="http://www.myscheme.com/schema">
<channel>
<item>
<title>A Simple Title</title>
<noo:subcategory>the sub category</noo:subcategory>
<noo:relatedInfos>
<noo:teams>
<noo:team id="3">New York</noo:team>
<noo:team id="4">Las Vegas</noo:team>
</noo:teams>
</noo:relatedInfos>
</item>
</channel>
</rss>
I am doing this php code to get the two "team" but it does not work ($xml has the previous content) :
$xml_datas = simplexml_load_string($xml);
foreach($xml_datas->channel->item as $item){
$noo = $item->children('noo');
echo $noo->team;
}
Do you have any idea why it is not working ?
Thanks
See if this helps:
<?php // RAY_temp_userco.php
error_reporting(E_ALL);
$xml = <<<ENDXML
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:noo="http://www.myscheme.com/schema">
<channel>
<item>
<title>A Simple Title</title>
<noo:subcategory>the sub category</noo:subcategory>
<noo:relatedInfos>
<noo:teams>
<noo:team id="3">New York</noo:team>
<noo:team id="4">Las Vegas</noo:team>
</noo:teams>
</noo:relatedInfos>
</item>
</channel>
</rss>
ENDXML;
$obj = simplexml_load_string($xml);
$ns = $obj->getNamespaces(TRUE);
foreach($obj->channel->item as $item){
$noo = $item->children($ns['noo']);
var_dump($noo);
}
"noo" is just a local alias for that namespace, and the ->children() method (and most XML handling functions) want to know its actual global identifier, which is the URI in the xmlns attribute.
You need to either specify the full identifier of the namespace (i.e. ->children('http://www.myscheme.com/schema')) or set the optional second parameter to tell SimpleXML to look up the prefix (->children('noo', true). The second may be more readable, but it will break if a future document has the same schema, but gives the namespace a different local alias.
Additionally, the team nodes aren't directly under the item node, so you need to traverse further to get them:
// Give the namespace a readable name that won't change
define('NS_NOO', 'http://www.myscheme.com/schema');
$xml_datas = simplexml_load_string($xml);
foreach($xml_datas->channel->item as $item){
$teams = $item->children(NS_NOO)->relatedInfo->teams;
echo $teams->team[0];
}
For example I have 2 types of nodes in my xml file:
1) <book>
2) <author>
A variable named $node points to specific node(of unknown type).
How can I access this node's name? It must be something like this:
if($node->name()=="book")
process_book($node);
else
process_author;
SimpleXMLElement has a getName() method:
echo $node->getName();
Assumption: $node is a SimpleXMLElement object.
I may be missing something, but here is a simlpe solution. Change simplexml_load_string to simplexml_load_file if your using a file.
$xml_string = <<<XML
<root>
<item>
<book>Book 1</book>
<author>Author 1</author>
</item>
<item>
<book>Book 2</book>
<author>Author 2</author>
</item>
<item>
<book>Book 3</book>
<author>Author 3</author>
</item>
</root>
XML;
$xml = simplexml_load_string($xml_string);
foreach($xml->item as $node){
if(isset($node->book)){
process_book($node);
}
}
i'm trying to pass an xml node to a function but can't figure out how - here's my xml markup:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<root>
<form>
<item>
<id>frm1</id>
<dbID>1</dbID>
<visible>1</visible>
</item>
</form>
<form>
<item>
<id>frm2</id>
<dbID>2</dbID>
<visible>1</visible>
</item>
</form>
</root>
when setting up a foreach loop - how's the syntax to iterate through the xml and passing the whole node to a function?
i've tried something like:
foreach($xml as $ctlXML => $value)
{
$ctl = generateCTL($ctlXML);
}
but it doesn't work as it should.
thanks
If you are using SimpleXML it is simple as
$xml = simplexml_load_file($path_to_file);
foreach($xml->form as $form){
$ctl = generateCTL($form->item);
}
Be careful - $form->item is an object