SimpleXML: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 163: Zeile 163:
 
Hinweis: Damit der Wert des Attributes als String ausgegeben wird muß man Casten (string) ansonsten wird ein Objekt zurück gegeben.
 
Hinweis: Damit der Wert des Attributes als String ausgegeben wird muß man Casten (string) ansonsten wird ein Objekt zurück gegeben.
  
=== Beispiel 2 ===
+
==== Beispiel 2 ====
  
 
Schneller Zugriff auf ein Attribut (Quelle php.net)
 
Schneller Zugriff auf ein Attribut (Quelle php.net)
Zeile 182: Zeile 182:
 
</pre>
 
</pre>
  
====Beispiel 3====
+
==== Beispiel 3 ====
 +
Schneller Zugriff mit Hilfsfunktion (Quelle: php.net)
  
 +
SimpleXMLElement Object
 +
<pre>
 +
(
 +
    [@attributes] => Array
 +
        (
 +
            [id] => 55555
 +
        )
 +
 +
    [text] => "hello world"
 +
)
 +
</pre>
 +
Funktion:
 +
<pre>
 +
<?php
 +
function xml_attribute($object, $attribute)
 +
{
 +
    if(isset($object[$attribute]))
 +
        return (string) $object[$attribute];
 +
}
 +
?>
 +
</pre>
 +
Nutzung:
 +
<pre>
 +
<?php
 +
print xml_attribute($xml, 'id'); //prints "55555"
 +
?>
 +
</pre>
 +
 +
==== 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):
 
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>

Version vom 14. August 2013, 06:59 Uhr

Simple XML ist eine PHP Schnittstelle zum Parsen von XML Dateien.

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

$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

xPath

<?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

Namespaces 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();
?>