SimpleXML
Simple XML ist eine PHP Schnittstelle zum Parsen von XML Dateien.
Links
SimpleXML ist gut zum Parsen, aber zum Schreiben von XML gibt es bessere Möglichkeiten
XML erzeugen
Einführung
Generelles vorgehen
- Einlesen der Daten (z.B. XML-Datei, oder String) in ein SimpleXML Objekt
- xpath Query auf das Objekt anwenden ($result= $sxe->xpath("Pfadangabe"). Man erhält ein Array mit SimpleXML Objekten
- Zugriff auf Werte und Attribute der simpleXML Objekte. Oft werden Sie dazu mit foreach in weitere Arrays eingelesen.
SimpleXML 101 - Empfehlungen zur Arbeit mit simpleXML
Quelle: http://stackoverflow.com/questions/1893024/basic-simplexml-working-example Zugriff 7/2013
Example:
<?xml version="1.0" encoding="ISO-8859-1"?> <programme> <title>Billy Bushwaka</title> <episodeNumber>2</episodeNumber> <description>Billy Bushwaka entertains</description> <url>play.swf</url> </programme>
First of all, always name your PHP variables after the node they represent.
// the root node is ie <programme/>
$programme = simplexml_load_file("local.xml");
Access to children (nodes) as if they were object properties.
echo $programme->title;
If there are multiple children using the same name, you can specify their 0-based position
// first <title/> child echo $programme->title[0];
// create or change the value of the second <title/> child $programme->title[1] = 'Second title';
Access to attributes as if they were array keys
// <mynode attr="attribute value" /> echo $mynode['attr'];
Manchmal muß man Casten (andere Möglichkeiten s.u.)
$myVal = (string)$mynode['attr'];
XPath always returns an array.
More Hints
Quick XML
$string = <<<XML <a> <foo name="one" game="lonely">1</foo> </a> XML;
Alternative xpath:
$result = $xml->xpath("//programme/title");
Quellcode der xml Datei ausgeben
echo $simplexml->asXML();
Snippets
XML-Datei von URL holen und in SimpleXML Objekt speichern
XML Daten von URL holen mit file_get_contents
Hier wird erst nach dem Laden konvertiert.
$url = "http://username:password@url.com"; $xml = file_get_contents($url); $data = new SimpleXMLElement($xml);
XML Daten mit simplexml_load_file
//einfache Variante
function fetch_xml_data($url){
$simplexml=simplexml_load_file(rawurlencode("https://".$this->user.":".$this->pw.'@'.$url));
$simplexml=simplexml_load_file("test.xml");
return $simplexml;
}
Manchmal erwartet der Server weitere Header. Dann muß man die Datei auf eine andere Weise mit Context laden (siehe Beispiel Mobile.de und Snippets)
Zusätzliche Header mit Stream Context senden
// Variante - Einlesen mit Context um diverse Header mit zu schicken
function fetch_xml_data_ctx($url){
// Erzeugen eines Streams
$headers = "Accept-language: de\r\n";
$headers .= "Accept: application/xml\r\n";
$headers .= "Authorization: Basic ".base64_encode("$this->user:$this->pw")."\r\n";
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> $headers
)
);
$context = stream_context_create($opts);
// Öffnen der Datei mit den oben definierten HTTP-Headern
$file = file_get_contents('https://'.$url, false, $context);
$simplexml=simplexml_load_string($file);
//print_r($file);
return $simplexml;
}
Zugriff auf Werte
Achtung: Wenn man die Werte über echo ausgibt wandelt sie PHP automatisch um damit sie angezeigt werden. Speichert man Sie hat man nur ein SimpleXMLObjekt um den Wert zu bekommen muß man es Casten.
Suche über xPath
xPath kann man als Suchpfad über die XML Hierarchie sehen.
<?php
$string = <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<d>
<c>code</c>
</d>
</a>
XML;
$xml = new SimpleXMLElement($string);
/* Search for <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo '/a/b/c: ',$node,"\n";
}
/* Relative paths also work... */
$result = $xml->xpath('b/c');
while(list( , $node) = each($result)) {
echo 'b/c: ',$node,"\n";
}
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
/a/b/c: text /a/b/c: stuff b/c: text b/c: stuff
Zugriff auf Attribute
Beispiel 1
Man lädt mittels foreach alle Attribute des SimpleXML Objektes in ein Array und greift dann darüber zu.
foreach( $sxe->attributes() as $attr_name => $attr_value ){
$arr['attributes'][(string)$attr_name] = (string)$attr_value;
}
Hinweis: Damit der Wert des Attributes als String ausgegeben wird muß man Casten (string) ansonsten wird ein Objekt zurück gegeben.
Beispiel 2
Schneller Zugriff auf ein Attribut (Quelle php.net)
<?php $att = 'attribueName'; // Zugriff : $attribute = $element->attributes()->$att; // Casting als String liefert den Wert (ansonsten das Objekt) $attribute = (string)$element->attributes()->$att; // Auch verändern des Wertes ist möglich : $element->attributes()->$att = 'New value of the attribute'; ?>
Beispiel 3
Schneller Zugriff mit Hilfsfunktion (Quelle: php.net)
SimpleXMLElement Object
(
[@attributes] => Array
(
[id] => 55555
)
[text] => "hello world"
)
Funktion:
<?php
function xml_attribute($object, $attribute)
{
if(isset($object[$attribute]))
return (string) $object[$attribute];
}
?>
Nutzung:
<?php print xml_attribute($xml, 'id'); //prints "55555" ?>
Beispiel 4
Ein Ergebnis aus xPath ist ein Array von $sxe Objekten und kann z.B. so aussehen (aus mobile.de mit var_dump ausgegeben):
array(1) {
[0]=>
object(SimpleXMLElement)#3 (1) {
["@attributes"]=>
array(4) {
["total"]=>
string(2) "85"
["page-size"]=>
string(2) "50"
["current-page"]=>
string(1) "1"
["max-pages"]=>
string(1) "2"
}
}
}
Darauf ist auch ein direkter Zugriff möglich:
private function parseResultInfo($sxe){
$arrInfo = array();
$xpath='//search:result'; // this works only if you have used the register_namespaces function in the snippets, otherwise you have to register xmlns:search="http://services.mobile.de/schema/search"
$result = $sxe->xpath($xpath);
//var_dump($result);
$arrInfo['total'] = (int)$result[0]['total'][0];
$arrInfo['page-size'] = (int)$result[0]['page-size'][0];
$arrInfo['current-page'] = (int)$result[0]['current-page'][0];
$arrInfo['max-pages'] = (int)$result[0]['max-pages'][0];
//print_r($arrInfo);
return $arrInfo;
}
Kindknoten abfragen
$children = $sxe->children($ns,TRUE);
$ns ist der Namespace, der zweite Parameter sagt ob rekursiv gesucht wird.
SimpleXML und Namespaces
Einfache Beispiele:
<root xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
<event:event>
<event:sessionKey></event:sessionKey>
<event:sessionName>Learn QB in Minutes</event:sessionName>
<event:sessionType>9</event:sessionType>
<event:hostWebExID></event:hostWebExID>
<event:startDate>02/12/2009</event:startDate>
<event:endDate>02/12/2009</event:endDate>
<event:timeZoneID>11</event:timeZoneID>
<event:duration>30</event:duration>
<event:description></event:description>
<event:status>NOT_INPROGRESS</event:status>
<event:panelists></event:panelists>
<event:listStatus>PUBLIC</event:listStatus>
</event:event>
...
</root>
Zugriff ohne Registrierung des Namespace
Dies setzt voraus, daß man sicher ist daß das xml immer den gleichen prefix verwendet.
$xml = new SimpleXMLElement($r);
foreach($xml->xpath('//event:event') as $event) {
var_export($event->xpath('event:sessionKey'));
}
Mit Registrierung der Namespaces
You have to register the namespace for each simpleXMLElement object you use.
$xml = new SimpleXMLElement($r);
$xml->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');
foreach($xml->xpath('//e:event') as $event) {
$event->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');
var_export($event->xpath('//e:sessionKey'));
}
The namespace should also be declared somewhere in the xml file.
<event:event xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
...
Umgehen von Namespaces über dom_import
$xml = new SimpleXMLElement($r);
$xml = dom_import_simplexml($xml);
$nodelist= $xml->getElementsByTagName('event');
for($i = 0; $i < $nodelist->length; $i++) {
$sessions = $nodelist->item($i)->getElementsByTagName('sessionKey');
echo $sessions->item(0)->nodeValue;
}
Funktion um Namespaces zu registrieren
Über eine kleine Funktion kann man sich arbeit sparen.
function register_namespaces($sxe){
$arrNs = $sxe->getNamespaces(true);
foreach($arrNs as $prefix => $ns){
$sxe->registerXPathNamespace($prefix, $ns);
echo($prefix.' = '.$ns);
}
}
Alle im XML Dokument angegebenen Namespaces werden geparsed und Registriert. So kann man sie in Kurzform ansprechen. (Siehe Beispiel Mobile.de)
Allgemein
$xml = <<<EOD
<book xmlns:chap="http://example.org/chapter-title">
<title>My Book</title>
<chapter id="1">
<chap:title>Chapter 1</chap:title>
<para>Donec velit. ...</para>
</chapter>
<chapter id="2">
<chap:title>Chapter 2</chap:title>
<para>Lorem ipsum ...</para>
</chapter>
</book>
EOD;
$sxe = new SimpleXMLElement($xml);
// Zugriff mit Namespace Prefix
$sxe->registerXPathNamespace('c', 'http://example.org/chapter-title');
$result = $sxe->xpath('//c:title');
foreach ($result as $title) {
echo $title . "\n";
}
Direkter Zugriff im nächsen Beispiel
Beispiel Ebay Timestamp
$response = <<< XMLBLOCK
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<GeteBayOfficialTimeResponse xmlns="urn:ebay:apis:eBLBaseComponents">
<Timestamp>2005-10-28T01:01:04.668Z</Timestamp>
<Ack>Success</Ack>
<Version>429</Version>
<Build>e429_intl_Bundled_1949355_R1</Build>
</GeteBayOfficialTimeResponse>
</soapenv:Body>
</soapenv:Envelope>
XMLBLOCK;
$xml = simplexml_load_string($response);
Zugriff auf Timestamp:
echo "Time: " .
$xml->children('http://schemas.xmlsoap.org/soap/envelope/')->children('urn:ebay:apis:eBLBaseComponents')->GeteBayOfficialTimeResponse->Timestamp . "\n";
oder
$xml->children('soapenv', true)->children()->GeteBayOfficialTimeResponse->Timestamp
Beispiele
Beispiel Mobile de
<?php
class Mobile{
var $arrNs = array();
public function init(){
$this->action = "";
$this->user = "username";
$this->pw = "passwort";
$this->customerId = "461731";
$this->clientId = "517329";
$this->baseUrl = "services.mobile.de/1.0.0/ad/search";
$arrResult = array(); // Contains last Result-List
}
public function main(){
$this->init();
$params = "?customerId=".$this->customerId."&page.size=100";
$url = $this->baseUrl.$params;
$this->sxe = $this->fetch_xml_data_ctx($url);
$this->register_namespaces();
$this->parseXML($this->sxe);
//$this->sxe_print_info();
$this->send_json($this->arrResult);
}
//Parse XML and create Array
private function parseXML($sxe){
$arrAds = array();
unset($this->arrResult);
// ADS
$xpath='//ad:ad';
$result = $sxe->xpath($xpath);
$count = 0;
if(count($result) > 0){
foreach ($result as $ad) {
// AUTO Parsing
$this->arrResult[ad][$count] = $this->sxe_to_array($ad,'ad');
// MANUAL Parsing
// Images
unset($arrImages);
$arrRepresentation = $ad->xpath('ad:images/ad:image/ad:representation');
foreach($arrRepresentation as $representation){
foreach($representation->attributes() as $key=>$val){
$arrImages[$key][]=(string)$val;
}
}
$this->arrResult[ad][$count]['images']= $arrImages;
$count += 1;
}
}
}
// Stores Attributes and Childs into Array
private function sxe_to_array(SimpleXMLElement $sxe,$ns){
$arr = array();
// ATTRIBUTES
$count=0;
foreach( $sxe->attributes() as $attr_name => $attr_value ){
$arr['attributes'][(string)$attr_name] = (string)$attr_value;
}
// CHILDREN
$children = $sxe->children($ns,TRUE);
$count = 0;
foreach($children as $child_name=>$child_node){
$arrChild = $this->sxe_to_array($child_node,$ns);
// RESSOURCE CHILD (ns resource)
$resources = $this->getResources($child_node);
//print_r($resources);
if(!empty($resources)) $arrChild['resources'] = $resources;
$arr['children'][$count][$child_name]['value']=(string)$child_node;
$arr['children'][$count][$child_name] = $arrChild;
}
return $arr;
}
private function getResources($node){
//add 'resource' namespace children (mobilede uses this as language descriptors)
$count = 0;
$ns="resource";
$arr = array();
$children = $node->children($ns,TRUE);
foreach($children as $resource_name=>$resource_node){
//print_r($resource_node);
$arrResource = $this->sxe_to_array($resource_node,$ns);
$arr[$count][$resource_name]['value']=(string)$resource_node;
//echo((string)$resource_node);
//$arr[$count][$resource_name] = $arrResource;
$count +=1;
}
return $arr;
}
private function sxe_print_info(){
$sxe = $this->sxe;
$namespaces = $sxe->getNamespaces(true);
echo("<br>##########<br><strong>namespaces:</strong> <br>");
foreach($namespaces as $key=>$val){
//echo("$key : $val<br>");
}
echo("<br>Name: ".$sxe->getName()."<br>");
//Print Ads Info
$xpath='//ad:ad';
$result = $this->sxe->xpath($xpath);
//echo("Number of ads: ".count($result)."<br><br>");
$count = 0;
//ADs
foreach ($result as $ad) {
$count += 1;
echo("<strong>Ad $count </strong><br>");
$ad_children = $ad->children('ad',TRUE);
//AD 1st Gen Children
if(count($ad_children) > 0){
foreach ($ad_children as $ad_child_name=>$ad_child_node){
echo("<strong>Childname: $ad_child_name</strong><br>");
// ATTRIBUTES
foreach($ad_child_node->attributes() as $key=>$val){
echo("<strong>Attributes:</strong> ");
echo("$key=$val<br>");
echo("<strong>Children: </strong><br>");
// Ad 2nd Gen Children
foreach($ad_child_node->children() as $ad_child_name=>$child_node){
echo("Name: $child_name<br>");
}
}
}
}
//$adurl = $ad->{'detail-page'}->value->attributes()->url;
//echo('<a href="'.$adurl.'" target="_blank">Link</a><br>');
}
}
function register_namespaces(){
$this->arrNs = $this->sxe->getNamespaces(true);
foreach($this->arrNs as $prefix => $ns){
$this->sxe->registerXPathNamespace($prefix, $ns);
}
}
function fetch_xml_data_ctx($url){
// Erzeugen eines Streams
$headers = "Accept-language: de\r\n";
$headers .= "Accept: application/xml\r\n";
$headers .= "Authorization: Basic ".base64_encode("$this->user:$this->pw")."\r\n";
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> $headers
)
);
$context = stream_context_create($opts);
// Öffnen der Datei mit den oben definierten HTTP-Headern
$file = file_get_contents('https://'.$url, false, $context);
$simplexml=simplexml_load_string($file);
//print_r($file);
return $simplexml;
}
function send_json($arrJSON){
// Wir geben der Anfrage ein JSON Objekt-Literal zurück
$ajax_return_data = json_encode($arrJSON);
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Length: '.strlen($ajax_return_data));
header('Content-Type: application/json; charset=UTF-8');
echo $ajax_return_data;
exit;
}
}
$mobile = new Mobile();
$mobile->main();
?>