1

I'm using SimpleXML to go through a kml doc, and I'm working on a project where I need to retrieve attributes in a specific order.

If I had something like this:

<Placemark>
<Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
<ExtendedData><SchemaData schemaUrl="#mizipirs">
    <SimpleData name="ZCTA5CE10">55555</SimpleData>
    <SimpleData name="GEOID10">55555</SimpleData>
    <SimpleData name="CLASSFP10">XX</SimpleData>
    <SimpleData name="MTFCC10">XXXXX</SimpleData>
    <SimpleData name="FUNCSTAT10">X</SimpleData>
    <SimpleData name="ZIPNUMERIC">XXXXX</SimpleData>
    <SimpleData name="ALAND10">XXXX</SimpleData>
    <SimpleData name="AWATER10">XXXX</SimpleData>
    <SimpleData name="INTPTLAT10">XX.XXXX</SimpleData>
    <SimpleData name="INTPTLON10">XX.XXXX</SimpleData>
    <SimpleData name="ZIPcode">XXXXX</SimpleData>
    <SimpleData name="AreaName">XXXXX</SimpleData>
    <SimpleData name="TaxYear">XXXXX</SimpleData>
    <SimpleData name="numreturns">XXX</SimpleData>
    <SimpleData name="numjointre">XXX</SimpleData>
    <SimpleData name="avg_agi">XXX</SimpleData>
</SchemaData></ExtendedData>
  <Polygon><outerBoundaryIs><LinearRing><coordinates>[lots of lat/lng data here removed for everyone's own convenience]</coordinates></LinearRing></outerBoundaryIs></Polygon>
</Placemark>

So if I wanted to access the SimpleData Value where the name = "ZIPcode" - is there a way I can do that? I have MANY <Placemark>'s in this document, so I can't use xpath, though I'm not even sure how I'd use Xpath based on an attribute. Maybe that's an option?

Edit

I'd love something like:

if(isset($xml->Document->Folder->Placemark)){
    foreach($xml->Document->Folder->Placemark as $place) {
        $zip = $place->xpath('//SchemaData/SimpleData[@name="ZIPcode"]/text()');
    }
}

The desired effect being that it pulls the value of the SimpleData element with the attribute of "ZIPcode", and it would do this for each Placemark element. But I can't get this code to return anything.

There's a little bit of the structure that was left out of the XML, but I left the necessary parts. If I left everything in, this would be a far larger document.

halfer
  • 19,824
  • 17
  • 99
  • 186
John Sly
  • 763
  • 1
  • 10
  • 31

3 Answers3

2

I don't get why you think this is not possible with XPath. In fact, it is one of the most basic use cases for XPath:

Placemark/ExtendedData/SchemaData/SimpleData[@name="ZIPcode"]/text()
dirkk
  • 6,160
  • 5
  • 33
  • 51
  • I didn't know the exact syntax for getting something by the attribute. I also assume the text() is a built in function to get the value? Is there a way to access this directly? Something like, "$place->ExtendedData->SchemaData->SimpleData[@name="ZIPcode"]->text()" - trying it, I get an error because of the "=". – John Sly Apr 09 '14 at 16:52
  • @JohnSly ok, I just assumend you already knew that as you actually did use the correct @ syntax in your question. Also, it is one of the first things you learn if you google for something with learning XPath. And yes, `text()` extracts the text value of an element. It is actually even better if you use `string()` if your processor supports it as it disregards comments. – dirkk Apr 09 '14 at 16:55
  • I appreciate the help. It's been a long time since I've used xpath so I was trying to do this from memory. I checked the basic useage and didn't see any examples on php.net that used xpath searches by the attribute (or maybe I completely missed them?). I thought it was possible though since, it seemed like a simple way to access the data. – John Sly Apr 09 '14 at 17:00
  • @JohnSly http://www.php.net/manual/en/simplexmlelement.xpath.php has same simple examples, also in the comments, some use attribute predicates. But of course there are better resources to look for XPath advice than the PHP manual – dirkk Apr 09 '14 at 17:05
  • So let me see if I can make this a little more complicated. foreach($xml->Document->Folder->Placemark as $place) { $test = $place->xpath('//SchemaData/SimpleData[@name="ZIPcode"]/text()'); } for the life of my, I cannot get this to work. The comment ignores the line breaks. I should include, the $place works, that's been tested locally. – John Sly Apr 09 '14 at 17:58
  • ok, it's been updated. I haven't been able to get xpath to return anything. I've even gone as far as checking my phpinfo to make sure it's set up like it is on another server I'm using where it works. – John Sly Apr 09 '14 at 19:25
  • @JohnSly The snippet you showed should work. I just tried to apply the XPath on the whole document and it return the correct result. Maybe there is something wrong with your `$Placemark`. – dirkk Apr 10 '14 at 11:41
  • I marked yours as correct. I found the issue elsewhere. My kml has a default namespace, which, even though it's default across the document, needs to be spelled out for the xpath. Your response was exactly correct for the question, just turns out my issue was outside of what was provided. I'm updating my question to mention that as well. – John Sly Apr 10 '14 at 13:28
0

(Posted on behalf of the question author).

I found the true issue. If your KML or XML has a default namespace, you must define that namespace with registerXPathNamespace("c","namespace here") and use it in your xpath calls such as $xml->xpath('//c:element').

I was not receiving any error messages, just retrieving an empty array each time.

halfer
  • 19,824
  • 17
  • 99
  • 186
-1

I know is a bit extreme, but why you don't grep or find the line that contains <SimpleData name="ZIPcode">

and on this line use substring or regex?

legrass
  • 407
  • 5
  • 13
  • Because it is a horrible solution if you have a valid XML file!? Why should one use a shovel if you have a excavator? – dirkk Apr 10 '14 at 11:30
  • @dirkk no need to get angry. I specified it's extreme and I suggested that as a last resort, because he explicitly said **I can't use xpath**. In this case, it would be still horrible but just a workaround to solve the problem. – legrass Apr 10 '14 at 11:39
  • I am not angry (I reserve that feeling for personal relationships). That he can not use XPath was clearly stated because the OP thought this is a task impossible to do with XPath (which is incorrect). Using grep to search within XML is just not a good idea: Your solution would already fail if there were additional attributes within a `` element. Also, as the OP now wants to search within each `` this would actually be more difficult using grep. – dirkk Apr 10 '14 at 11:58
  • And as you are fairly new to SO: This isn't actually an answer, it is more the idea of an answer. An actual answer should contain a more specific solution, i.e. which commands to execute. – dirkk Apr 10 '14 at 12:01