I'm not to experienced with XML and I have been trying to figure this out without to much progress.
I need to get the results from the XML file to a array using PHP.
Here is the XML
<ns2:messageContainer xmlns="datex2.eu/schema/3/common" xmlns:ns2="datex2.eu/schema/3/messageContainer" xmlns:ns3="datex2.eu/schema/3/exchangeInformation" xmlns:ns4="datex2.eu/schema/3/informationManagement" xmlns:ns5="datex2.eu/schema/3/dataDictionaryExtension" xmlns:ns6="datex2.eu/schema/3/cctvExtension" xmlns:ns7="datex2.eu/schema/3/locationReferencing" xmlns:ns8="datex2.eu/schema/3/alertCLocationCodeTableExtension" xmlns:ns9="datex2.eu/schema/3/extension" xmlns:ns10="datex2.eu/schema/3/roadTrafficData" xmlns:ns11="datex2.eu/schema/3/vms" xmlns:ns12="datex2.eu/schema/3/situation" modelBaseVersion="3">
<ns2:payload xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns7:PredefinedLocationsPublication" lang="no" modelBaseVersion="3">
<publicationTime>2023-01-25T13:56:15.615+01:00</publicationTime>
<publicationCreator>
<country>no</country>
<nationalIdentifier>NPRA</nationalIdentifier>
</publicationCreator>
<ns7:headerInformation>
<confidentiality>noRestriction</confidentiality>
<informationStatus>real</informationStatus>
</ns7:headerInformation>
<ns7:predefinedLocationReference xsi:type="ns7:PredefinedLocation" id="100356" version="1">
<ns7:predefinedLocationName>
<values>
<value lang="no">Eikås - Åsanevegen</value>
</values>
</ns7:predefinedLocationName>
<ns7:location xsi:type="ns7:LinearLocation">
<ns7:gmlLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#32633">
<ns7:posList>-27946 6743813</ns7:posList>
</ns7:gmlLineString>
</ns7:location>
</ns7:predefinedLocationReference>
<ns7:predefinedLocationReference xsi:type="ns7:PredefinedLocation" id="100361" version="1">
<ns7:predefinedLocationName>
<values>
<value lang="no">Ammerud - Bjerke</value>
</values>
</ns7:predefinedLocationName>
<ns7:location xsi:type="ns7:LinearLocation">
<ns7:gmlLineString srsName="http://www.opengis.net/gml/srs/epsg.xml#32633">
<ns7:posList>269553 6653843</ns7:posList>
</ns7:gmlLineString>
</ns7:location>
</ns7:predefinedLocationReference>
</ns2:payload>
<ns2:exchangeInformation modelBaseVersion="3">
<ns3:exchangeContext>
<ns3:codedExchangeProtocol>snapshotPull</ns3:codedExchangeProtocol>
<ns3:exchangeSpecificationVersion>3</ns3:exchangeSpecificationVersion>
<ns3:supplierOrCisRequester>
<ns3:internationalIdentifier>
<country>no</country>
<nationalIdentifier>NPRA</nationalIdentifier>
</ns3:internationalIdentifier>
</ns3:supplierOrCisRequester>
</ns3:exchangeContext>
<ns3:dynamicInformation>
<ns3:exchangeStatus>undefined</ns3:exchangeStatus>
<ns3:messageGenerationTimestamp>2023-01-25T13:56:15.615+01:00</ns3:messageGenerationTimestamp>
</ns3:dynamicInformation>
</ns2:exchangeInformation>
</ns2:messageContainer>
Here is my PHP code
$xml = simplexml_load_string($response->raw_body, "SimpleXMLElement", LIBXML_NOCDATA, 'ns2', true);
$xml->registerXPathNamespace('ns7','http://datex2.eu/schema/3/locationReferencing');
$count = 0;
foreach($xml->xpath('//ns7:predefinedLocationReference') as $event) {
$return[$count]['id'] = intval($event->attributes()->id);
$predefinedLocationName = $event->xpath('ns7:predefinedLocationName');
foreach ($predefinedLocationName[0]->values as $locVal) {
$return[$count]['name'] = strval($locVal->value);
}
$count++;
}
I'm sure there is a better way but here is what I got:
{
"id": 100356,
"name": "Eikås - Åsanevegen"
},
{
"id": 100361,
"name": "Ammerud - Bjerke"
}
What I'm missing is to get out the posList value from the XML and add it to my array in PHP
Rather than messing around with XPath, I would use the main SimpleXML access methods, noting this reference of how SimpleXML handles namespaces.
Specifically, I would note down the path I wanted to take through the document, expanding namespaces to their full identifiers rather than their local aliases:
messageContainer
, in the datex2.eu/schema/3/messageContainer
namespacepayload
, in the same namespacepredefinedLocationReference
, in the datex2.eu/schema/3/locationReferencing
namespaceid
attributepredefinedLocationName
, still in the datex2.eu/schema/3/locationReferencing
namespacevalues
, in the datex2.eu/schema/3/common
namespace (defined as the default xmlns
at the top of the document)value
element in that namespacepredefinedLocationReference
we had earlier, go into the location
(in the same namespace as predefinedLocationReference
)gmlLineString
, in the same namespaceposList
, in the same namespaceThat then translates directly to this PHP code:
// Some constants to make namespaces easier to read
const NS_MSG_CONT = 'datex2.eu/schema/3/messageContainer';
const NS_LOC_REF = 'datex2.eu/schema/3/locationReferencing';
const NS_COMMON = 'datex2.eu/schema/3/common';
// Initialise our return array
$return = [];
// Start at `messageContainer`, in the `datex2.eu/schema/3/messageContainer` namespace
$xml = simplexml_load_string($response->raw_body, "SimpleXMLElement", 0, NS_MSG_CONT);
// Go into `payload`, in the same namespace
$payload = $xml->payload;
// Loop over each `predefinedLocationReference`, in the `datex2.eu/schema/3/locationReferencing` namespace
foreach ($payload->children(NS_LOC_REF)->predefinedLocationReference as $predefinedLocationReference ) {
// Initialise the return item
$item = [];
// Get the "id" from the (non-namespaced) `id` attribute
$item['id'] = (string)$predefinedLocationReference->attributes(null)->id;
// Go into `predefinedLocationName`, still in the `datex2.eu/schema/3/locationReferencing` namespace
$predefinedLocationName = $predefinedLocationReference->predefinedLocationName;
// Go into `values`, in the `datex2.eu/schema/3/common` namespace (defined as the default `xmlns` at the top of the document)
$values = $predefinedLocationName->children(NS_COMMON)->values;
// Get the "name" from the `value` element in that namespace
$item['name'] = (string)$values->value;
// From the `predefinedLocationReference` we had earlier, go into the `location` (in the same namespace as `predefinedLocationReference`)
$location = $predefinedLocationReference->location;
// Go into `gmlLineString`, in the same namespace
$gmlLineString = $location->gmlLineString;
// Get the "posList" from the `posList`, in the same namespace
$item['posList'] = (string)$gmlLineString->posList;
// Add item to our final results
$return[] = $item;
}
// Test
var_dump($return);
This can obviously be made much shorter by removing comments and intermediate variables to taste; a very shortened version of exactly the same code looks like this:
const NS_MSG_CONT = 'datex2.eu/schema/3/messageContainer';
const NS_LOC_REF = 'datex2.eu/schema/3/locationReferencing';
const NS_COMMON = 'datex2.eu/schema/3/common';
$xml = simplexml_load_string($raw_body, "SimpleXMLElement", 0, NS_MSG_CONT);
// Note: in PHP >8.0, you can skip the parameters you're not interested in:
// $xml = simplexml_load_string($raw_body, namespace_or_prefix: NS_MSG_CONT);
$return = [];
foreach ($xml->payload->children(NS_LOC_REF)->predefinedLocationReference as $predefinedLocationReference ) {
$return[] = [
'id' => (string)$predefinedLocationReference->attributes(null)->id,
'name' => (string)$predefinedLocationReference->predefinedLocationName->children(NS_COMMON)->values->value,
'posList' => (string)$predefinedLocationReference->location->gmlLineString->posList,
];
}