SimpleXML: Unterschied zwischen den Versionen
| (7 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
Simple XML ist eine PHP Schnittstelle zum Parsen von XML Dateien. | 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 == | == Einführung == | ||
== Generelles vorgehen == | == Generelles vorgehen == | ||
* Einlesen der Daten (z.B. XML-Datei, oder String) in ein '''SimpleXML Objekt''' | * 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''' | + | * '''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. | * Zugriff auf Werte und Attribute der simpleXML Objekte. Oft werden Sie dazu mit foreach in weitere Arrays eingelesen. | ||
| Zeile 110: | Zeile 114: | ||
</pre> | </pre> | ||
=== Zugriff auf Werte === | === 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 ==== | ==== Suche über xPath ==== | ||
| Zeile 216: | Zeile 221: | ||
==== Beispiel 4 ==== | ==== 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): | |
<pre> | <pre> | ||
array(1) { | array(1) { | ||
| Zeile 258: | Zeile 263: | ||
== SimpleXML und Namespaces == | == SimpleXML und Namespaces == | ||
| − | === Namespaces registrieren === | + | |
| + | === Einfache Beispiele: === | ||
| + | |||
| + | <syntaxhighlight lang="xml"> | ||
| + | <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> | ||
| + | </syntaxhighlight> | ||
| + | ==== Zugriff ohne Registrierung des Namespace ==== | ||
| + | Dies setzt voraus, daß man sicher ist daß das xml immer den gleichen prefix verwendet. | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $xml = new SimpleXMLElement($r); | ||
| + | |||
| + | foreach($xml->xpath('//event:event') as $event) { | ||
| + | var_export($event->xpath('event:sessionKey')); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | ==== Mit Registrierung der Namespaces ==== | ||
| + | |||
| + | You have to register the namespace for each simpleXMLElement object you use. | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $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')); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | The namespace should also be declared somewhere in the xml file. | ||
| + | <syntaxhighlight lang="xml"> | ||
| + | <event:event xmlns:event="http://www.webex.com/schemas/2002/06/service/event"> | ||
| + | ... | ||
| + | </syntaxhighlight> | ||
| + | ==== Umgehen von Namespaces über dom_import ==== | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $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; | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | === Funktion um Namespaces zu registrieren === | ||
Über eine kleine Funktion kann man sich arbeit sparen. | Über eine kleine Funktion kann man sich arbeit sparen. | ||
<pre> | <pre> | ||
| Zeile 517: | Zeile 580: | ||
?> | ?> | ||
</pre> | </pre> | ||
| + | |||
| + | ===XML from Scratch=== | ||
| + | Zum Erzeugen von XML gibt es bessere Möglichkeiten aber es funktioniert auch mit SimpleXML: | ||
| + | <syntaxhighlight lang="php"> | ||
| + | <?php | ||
| + | $newsXML = new SimpleXMLElement("<news></news>"); | ||
| + | $newsXML->addAttribute('newsPagePrefix', 'value goes here'); | ||
| + | $newsIntro = $newsXML->addChild('content'); | ||
| + | $newsIntro->addAttribute('type', 'latest'); | ||
| + | Header('Content-type: text/xml'); | ||
| + | echo $newsXML->asXML(); | ||
| + | ?> | ||
| + | </syntaxhighlight> | ||
Aktuelle Version vom 22. September 2021, 16:11 Uhr
Simple XML ist eine PHP Schnittstelle zum Parsen von XML Dateien.
Links[Bearbeiten]
SimpleXML ist gut zum Parsen, aber zum Schreiben von XML gibt es bessere Möglichkeiten
XML erzeugen
Einführung[Bearbeiten]
Generelles vorgehen[Bearbeiten]
- 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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
echo $simplexml->asXML();
Snippets[Bearbeiten]
XML-Datei von URL holen und in SimpleXML Objekt speichern[Bearbeiten]
XML Daten von URL holen mit file_get_contents[Bearbeiten]
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[Bearbeiten]
//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[Bearbeiten]
// 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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
Beispiel 1[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
$children = $sxe->children($ns,TRUE);
$ns ist der Namespace, der zweite Parameter sagt ob rekursiv gesucht wird.
SimpleXML und Namespaces[Bearbeiten]
Einfache Beispiele:[Bearbeiten]
<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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
$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[Bearbeiten]
Ü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[Bearbeiten]
$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[Bearbeiten]
$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[Bearbeiten]
Beispiel Mobile de[Bearbeiten]
<?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();
?>
XML from Scratch[Bearbeiten]
Zum Erzeugen von XML gibt es bessere Möglichkeiten aber es funktioniert auch mit SimpleXML:
<?php
$newsXML = new SimpleXMLElement("<news></news>");
$newsXML->addAttribute('newsPagePrefix', 'value goes here');
$newsIntro = $newsXML->addChild('content');
$newsIntro->addAttribute('type', 'latest');
Header('Content-type: text/xml');
echo $newsXML->asXML();
?>