I have created a android app that gets the gpslocation and creates a url:
https://maps.googleapis.com/maps/api/geocode/xml?latlng=00.00,00.00&sensor=true
Example:
https://maps.googleapis.com/maps/api/geocode/xml?latlng=42.120636,-72.568731&sensor=true
This returns (only a part):
<GeocodeResponse>
<status>OK</status>
<result>
<type>street_address</type>
<formatted_address>
17 Dorchester Street, Springfield, Massachusetts 01109, United States
</formatted_address>
<address_component>
<long_name>17</long_name>
<short_name>17</short_name>
<type> ...
And i'm interested in this part: 17 Dorchester Street, Springfield, Massachusetts 01109, United States.
And I would like to create a new url that contains the zip number code "01109" like
http://mysite.com?process=01109 and open this site.
Can anyone help me!
So, the XML you link to actually has the postal code in it. It is an address_component with a child type that has the value postal_code. The easiest way to get there, IMHO, is XPath:
$d = <<<HER
<GeocodeResponse>
<!-- yada... -->
<result>
<!-- yada -->
<address_component>
<long_name>01109</long_name>
<short_name>01109</short_name>
<type>postal_code</type>
</address_component>
<!-- yada -->
</result>
<!-- yoda -->
</GeocodeResponse>
HER;
$doc = new DomDocument();
$doc->loadXML($d);
$path = new DomXPath($doc);
/*
the query translates->
// = all nodes
address_component = which have the type of 'address_component'
type = the children of the address_component with the type 'type'
[text() = "postal_code"] = but only the type's with the value 'postal_code'
/preceding-sibling = all nodes before this one in the same parent
::*[1] = the one most adjacent of the sibling
*/
$p = $path->query(
'//address_component/type[text() = "postal_code"]/preceding-sibling::*[1]');
$newUrl = 'http://mysite.com?process='.$p->item(0)->nodeValue;
print($newUrl);
To obtain specific data from the googleapis geocode response you not only need to locate an element by it's name but also by it's content.
This can be easily done with Xpath. Luckily the SimpleXML extension in PHP has good support for reading such common formatted XML documents.
First for the Xpath:
<GeocodeResponse>
<result>
<type>street_address</type>
The <result> element is the element that has a child <type> which node-value is street_address. In Xpath this is expressed as:
/*/result/type[. = "street_address"]/..
And it works similar for the ZIP-code. It is the <address_component> child of the previous <result> node that has a child <type> which node-value is postal_code and of that element you want:
address_component/type[. = "postal_code"]/..
So far for the xpaths. All you need to get this to run is to load the XML document, execute the paths and read out the values you're interested in:
$xml = simplexml_load_file($xmlFile);
list($result) = $xml->xpath('/*/result/type[. = "street_address"]/..');
list($postal_code) = $result->xpath('address_component/type[. = "postal_code"]/..');
echo $result->formatted_address, "\nZIP: ", $postal_code->long_name, "\n";
With the XML documented linked in your question this creates the following output:
17 Dorchester Street, Springfield, MA 01109, USA
ZIP: 01109
I hope this is helpful.
You can access the postal_code short_name using simplexml and xpath. Here's a working example:
$location = simplexml_load_file('https://maps.googleapis.com/maps/api/geocode/xml?latlng=42.120636,-72.568731&sensor=true');
$postal_code_search =
$location->xpath('//result[type="street_address"]/address_component[type="postal_code"]/short_name');
$postal_code = (string) $postal_code_search[0];
Notice that you must cast the values to string explicitly, as simplexml will return array or object to variables versus a string when printed (which can be confusing when testing).
Related
I have an XML structure like this
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
<county>
</location>
</company>
</companies>
I am trying to get specific info from the elements into PHP variables.
To get "vatno" I use:
$vatno = $xmlObject->item($i)->getElementsByTagName('vatno')->item(0)->childNodes->item(0)->nodeValue;
But what if I need the county name for example?
I cannot use getElementsByTagName('text') as it would get the company name also using the element name "text".
You may be better off using SimpleXML, you can then access the various components in a more intuitive way.
The example above would be something like...
$data = <<< XML
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
</county>
</location>
</company>
</companies>
XML;
$xml = simplexml_load_string($data);
foreach ( $xml->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
So each sub element is accessed using ->.
If you wanted to stick with what you already had, you should be able to use...
$countyName = $xmlObject->item($i)->getElementsByTagName('text')->item(1)
->nodeValue;
Using item(1) will fetch the second instance of the <text> elements, so this assumes that the name will have this value as well.
It works with SimpleXML if I use
$xml = simplexml_load_string($data);
foreach ( $xml->companies->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
This is my XML file named: full.xml
I need your help. I need a PHP script that open "full.xml"
and only display all values of the nodes that have .email
Example of the Output I want:
sales#company1.com
sales#company2.com
sales#company3.com
Thanks! I will thank you so much!
EDIT
$Connect = simplexml_load_file("full.xml");
return $Connect->table[0]->*.email;
The design of your XML is not very smart. With this xpath expression, you select all nodes with .email at the end of their name:
$xml = simplexml_load_string($x); // assume XML in $x
$results = $xml->xpath("//*[substring(name(),string-length(name())-" . (strlen('.email') - 1) . ") = '.email']");
--> result is an array with the selected nodes.
BTW: if you have any chance of CHANGING the structure of the XML, AVOID combining information within node names like <company1.email>, but do it like this:
...
<companies>
<company id="1">
<email>info#company1.com</email>
<tel>+498988123456</tel>
<name>somename</name>
</company>
<company id="2">
<email>info#company2.com</email>
<tel>+498988123457</tel>
<name>someothername</name>
</company>
</companies>
....
It will be much easier to read and parse.
I have the following XML file loaded into php simplexml.
<adf>
<prospect>
<customer>
<name part="first">Bob</name>
<name part="last">Smith</name>
</customer>
</prospect>
</adf>
using
$customers = new SimpleXMLElement($xmlstring);
This will return "Bob" but how do I return the last name?
echo $customers->prospect[0]->customer->contact->name;
You can access the different <name> elements by number, using array-style syntax.
$names = $customers->prospect[0]->customer->name;
echo $names[0]; // Bob
echo $names[1]; // Smith
In fact, you're already doing it for the <prospect> element!
See also Basic SimpleXML Usage in the manual.
If you want to select elements based on some criteria, then XPath is the tool to use.
$customer = $customers->prospect[0]->customer;
$last_names = $customer->xpath('name[#part="last"]'); // always returns an array
echo $last_names[0]; // Smith
i hv a xml file,how to get values in title field using get file content method..i just want to get the value "TomTom XXL 550M - US, Canada & Mexico Automotive GPS. (Brand New)"
<Title>
TomTom XXL 550M - US, Canada & Mexico Automotive GPS. (Brand New)
</Title>
my code
$xmlstr = file_get_contents($source);
$parseXML = new SimpleXMLElement($xmlstr);
print($parseXML);
// load as file
$parseXMLFile = new SimpleXMLElement($source,null,true);
If you feel confortable with javascript, there is another solution called DOMDocument
You can load XML files and also use function like getElementsByTagName. For example, if you have a books.xml file like this:
<?xml version="1.0" encoding="utf-8"?>
<books>
<book><title>Patterns of Enterprise Application Architecture</title></book>
<book><title>Design Patterns: Elements of Reusable Software Design</title></book>
<book><title>Clean Code</title></book>
</books>
You can extract titles so:
$dom = new DOMDocument;
$dom->load('books.xml');
$books = $dom->getElementsByTagName('title');
foreach ($books as $book) {
echo $book->nodeValue.'<br>';
}
You just have to read your file with simplexml_load_file : Doc for this one
You will then get object of class SimpleXMLElement.
Then, you can use it to get what you want ! Some examples here : SimpleXML Examples
I have a question concerning a good strategy on how to fill a data "bean" with data inside an xml file.
The bean might look like this:
class Person
{
var $id;
var $forename = "";
var $surname = "";
var $bio = new Biography();
}
class Biography
{
var $url = "";
var $id;
}
the xml subtree containing the info might look like this:
<root>
<!-- some more parent elements before node(s) of interest -->
<person>
<name pre="forename">
Foo
</name>
<name pre="surname">
Bar
</name>
<id>
1254
</id>
<biography>
<url>
http://www.someurl.com
</url>
<id>
5488
</id>
</biography>
</person>
</root>
At the moment, I have one approach using DOMDocument. A method
iterates over the entries and fills the bean by "remembering"
the last node. I think thats not a good approach.
What I have in mind is something like preconstructing some xpath
expression(s) and then iterate over the subtrees/nodeLists. Return
an array containing the beans as defined above eventually.
However, it seems not to be possible reusing a subtree /DOMNode
as DOMXPath constructor parameter.
Has anyone of you encountered such a problem?
Did you mean using an XML file as a sort of template ?
You can use some factory to build the empty person or biography node and then feed it, or validate using DTD's
You can search using xpath on selected DOM nodes, see php DOMXpath manual
no. The XML contains real data. I need to transform it into a php array (unfortunenatly it must be PHP :/ don't ask why ...).
---> You can use some factory to build the empty person or biography node and then feed it, or validate using DTD's
The "bean" is not the problem ... Constructing the list of beans is harder than i thought.. maybe the main problem is related to the solution, since I want to keep it as general as possible ..
here is some java code I just wrote, maybe you get an idea..
public List<PersonBean> extract(String xml) throws Exception {
InputSource is =new InputSource(new StringReader(xml));
XPathFactory xfactory = XPathFactory.newInstance();
XPath xpath = xfactory.newXPath();
NodeList nodeList = (NodeList)xpath.evaluate("/root/person", is, XPathConstants.NODESET);
int length = nodeList.getLength();
int pos = -1;
Traverser tra = new Traverser();
Attribute nameAttr = new Attribute();
nameAttr.setName("attr");
while(++pos < length) {
PersonBean bean = new PersonBean();
Node person = nodeList.item(pos);
Node fore = tra.getElementByNodeName(person, "id");
nameAttr.setValue("forename");
Node pre = tra.getElementByNodeNameWithAttribute(person,"name",nameAttr);
nameAttr.setValue("surname");
Node sur = tra.getElementByNodeNameWithAttribute(person, "name", nameAttr);
bean.setForeName(pre.getTextContent());
bean.setSurName(sur.getTextContent());
bean.setId(fore.getTextContent());
Node bio = tra.getElementByNodeName(person, "biography");
Node bid = tra.getElementByNodeName(bio, "id");
Node url = tra.getElementByNodeName(bio, "url");
BiographyBean bioBean = new BiographyBean();
bioBean.setId(bid.getTextContent());
bioBean.setUrl(url.getTextContent());
bean.setBio(bioBean);
persons.add(bean);
}
return persons;
}
Traverser is just a simple iterative xml traverser ..
Attribute another Bean for Value and Name.
This solution works fine, given the case there is a "person"-node.. However, the code could grow drastically for all other elements that need to be parsed..
I don't expect ready made solutions, just a small hint in the right direction.. :)
Cheers,
Mike