PHP xpath query with namespaces returns broken nodes

106 Views Asked by At

I try to parse wfs xml structures with PHP 8.1 and have the following snippet:

<?php

$rawContent = file_get_contents('https://www.geobasisdaten.niedersachsen.de/doorman/noauth/WFS_NI_2211_ATKIS_BDLM-Modell-konform?request=getCapabilities&service=wfs&version=1.1.0');
// source: https://numis.niedersachsen.de/trefferanzeige?docuuid=e26aebd6-cc4c-4af2-8be3-8719b808df5d&plugid=/ingrid-group:iplug-csw-dsc-lgln&docid=julvu30Bh4CjFjsS0QgC

// the following works fine:
// $rawContent = file_get_contents('https://pegelonline.wsv.de/webservices/gis/aktuell/wfs?request=GetCapabilities&service=WFS&typename=gk%3Awaterlevels&version=1.1.0');
// source: https://pegelonline.wsv.de

$wfsStructure= new \SimpleXMLElement($rawContent);

$wfsStructure->registerXPathNamespace('wfs', 'http://www.opengis.net/wfs');
$wfsStructure->registerXPathNamespace('ows', 'http://www.opengis.net/ows/1.1');
$wfsStructure->registerXPathNamespace('ogc', 'http://www.opengis.net/ogc');

$resultList = $wfsStructure->xpath('//*[local-name()=\'FeatureType\']');
// same result with following xpath
// $resultList = $wfsStructure->xpath('/wfs:WFS_Capabilities/wfs:FeatureTypeList//wfs:FeatureType');

var_dump($resultList);

The result is kind of boring:

array(105) {
  [0]=>
  object(SimpleXMLElement)#2 (0) {
  }
  [1]=>
  object(SimpleXMLElement)#3 (0) {
  }
  [2]=>
  object(SimpleXMLElement)#4 (0) {
  }
  (…)
  [103]=>
  object(SimpleXMLElement)#105 (0) {
  }
  [104]=>
  object(SimpleXMLElement)#106 (0) {
  }
}

So my script detects 104 nodes, but all of them are empty. Do you have any clues why I’m stepping in trouble there? When I call the other wfs source commented in the script above, everything works fine.

2

There are 2 best solutions below

3
On

You need a couple of tweaks - for example, $resultList = $wfsStructure->xpath('//*[local-name()=\'FeatureType\']'); doesn't work because you have a single quote sorrounding a single quote instead of a double quote).

Try it like this and see if it works. For example, to get the text values of all the <wfs:OtherSRS> nodes which are children of the 2nd <wfs:FeatureType> node:

$wfsStructure= new SimpleXMLElement($rawContent);    
$wfsStructure->registerXPathNamespace('wfs', 'http://www.opengis.net/wfs');
$resultList = $wfsStructure->xpath('//wfs:FeatureTypeList//wfs:FeatureType[2]//wfs:OtherSRS');    
foreach ($resultList as $result){
      echo($result[0]."\n");
}

The output should be:

urn:ogc:def:crs:EPSG::25833
urn:ogc:def:crs:EPSG::3034
urn:ogc:def:crs:EPSG::3857
urn:ogc:def:crs:EPSG::4258
urn:ogc:def:crs:EPSG::4326
urn:ogc:def:crs:EPSG::900913
0
On

Okay, next clue I guess: The wfs file https://www.geobasisdaten.niedersachsen.de/doorman/noauth/WFS_NI_2211_ATKIS_BDLM-Modell-konform?request=getCapabilities&service=wfs&version=1.1.0 does not match the wfs schema as it has some more wfs namespaces on elements which shouldn’t have a wfs namespace.

When I remove that wfs namespaces manually before converting the file into a SimpleXMLElement, everything works fine.

$rawContent = str_replace('wfs:FeatureType', 'FeatureType', $rawContent);
$rawContent = str_replace('wfs:Name', 'Name', $rawContent);
$rawContent = str_replace('wfs:Title', 'Title', $rawContent);

But I guess, nobody should ever see this approach as I would never ever get a job again.