Download presentation
Presentation is loading. Please wait.
1
Advanced XML and Web Services
September 12, 2006 Robert Richards
2
Agenda Introduction to Terms and Concepts Libxml DOM SimpleXML
SAX (ext/xml) XMLReader XSL XMLWriter SOAP (ext/soap)
3
XML Namespaces An XML Namespace is a collection of names identified by a URI. They are applicable to elements and attributes. Namespaces may or may not be associated with a prefix. xmlns:rob="urn:rob" xmlns= Attributes never reside within a default namespace. It is illegal to have two attributes with the same localname and same namespace on the same element.
4
XML Namespace Example <order num="1001"> <shipping>
<name type="care_of">John Smith</name> <address>123 Here</address> </shipping> <billing> <name type="legal">Jane Doe</name> <address>456 Somewhere else</address> </billing> </order>
5
XML Namespace Example <order num="1001" xmlns="urn:order"
xmlns:ship="urn:shipping" xmlns:bill="urn:billing"> <ship:shipping> <ship:name type="care_of">John Smith</ship:name> <ship:address>123 Here</ship:address> </ship:shipping> <bill:billing> <bill:name type="legal">Jane Doe</bill:name> <bill:address>456 Somewhere else</bill:address> </bill:billing> </order>
6
Illegal Namespace Usage
<order num="1001" xmlns="urn:order" xmlns:order="urn:order" xmlns:ship="urn:order"> <shipping ship:type="fed_ex" type="fed_ex"> <name ship:type="care_of" order:type="legal">John Smith</ship:name> </ship:shipping> </order>
7
Illegal Namespace Usage
<order num="1001" xmlns="urn:order" xmlns:order="urn:order" xmlns:ship="urn:order"> <shipping ship:type="fed_ex" type="fed_ex"> <name ship:type="care_of" order:type="legal">John Smith</ship:name> </ship:shipping> </order> <!-- attributes on shipping element are valid ! -->
8
Reserved Namespaces and Prefixes
The prefix xml is bound to The prefix xmlns is bound to Prefixes should also not begin with the characters xml.
9
Schemas and Validation
Validation insures an XML document conforms to a set of defined rules. Multiple mechanisms exist to write document rule sets: Document Type Definition (DTD) XML Schema RelaxNG
10
Document Type Definition (DTD) validation/courses-dtd.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE courses [ <!ELEMENT courses (course+)> <!ELEMENT course (title, description, credits, lastmodified)> <!ATTLIST course cid ID #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT description (#PCDATA)> <!ELEMENT credits (#PCDATA)> <!ELEMENT lastmodified (#PCDATA)> ]> <courses> <course cid="c1"> <title>Basic Languages</title> <description>Introduction to Languages</description> <credits>1.5</credits> <lastmodified> T11:13:01</lastmodified> </course> <course cid="c2"> . . . </courses>
11
DTD and IDs validation/course-id.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE courses [ <!ATTLIST course cid ID #REQUIRED> ]> <courses> <course cid="c1"> <title xml:id="t1">Basic Languages</title> <description>Introduction to Languages</description> </course> <course cid="c2"> <title xml:id="t3">French I</title> <description>Introduction to French</description> <course cid="c3"> <title xml:id="t3">French II</title> <description>Intermediate French</description> </courses>
12
XML Schema validation/course.xsd
<?xml version="1.0"?> <xsd:schema xmlns:xsd=" <xsd:element name="courses"> <xsd:complexType> <xsd:sequence> <xsd:element name="course" minOccurs="1" maxOccurs="unbounded"> <xsd:element name="title" type="xsd:string"/> <xsd:element name="description" type="xsd:string"/> <xsd:element name="credits" type="xsd:decimal"/> <xsd:element name="lastmodified" type="xsd:dateTime"/> </xsd:sequence> <xsd:attribute name="cid" type="xsd:ID"/> </xsd:complexType> </xsd:element> </xsd:schema>
13
RelaxNG validation/course.rng
<grammar xmlns=" datatypeLibrary=" <start> <element name="courses"> <zeroOrMore> <element name="course"> <attribute name="cid"><data type="ID"/></attribute> <element name="title"><text/></element> <element name="description"><text/></element> <element name="credits"><data type="decimal"/></element> <element name="lastmodified"><data type="dateTime"/></element> </element> </zeroOrMore> </start> </grammar>
14
XPath Language to locate and retrieve information from an XML document
A foundation for XSLT An XML document is a tree containing nodes The XML document is the root node Locations are addressable similar to the syntax for a filesystem
15
XPath Reference Document xpath/courses.xml
<courses xmlns:t=" <course xml:id="c1"> <t:title>Basic Languages</t:title> <description>Introduction to Languages</description> </course> <course xml:id="c2"> <t:title>French I</t:title> <description>Introduction to French</description> <course xml:id="c3"> <t:title>French II</t:title> <description>Intermediate French</description> <pre-requisite cref="c2" /> <?phpx A PI Node ?> <defns xmlns="urn:default">content</defns> </courses>
16
XPath Location Example xpath/location.php
Expression: /courses/course/description //description /courses/*/description //description[ancestor::course] Resulting Nodset: <description>Introduction to Languages</description> <description>Introduction to French</description> <description>Intermediate French</description>
17
XPath Function Example xpath/function.php
French II Intermediate French content
18
XPath and Namespaces xpath/namespaces.php
//title Empty NodeSet //t:title <t:title>Basic Languages</t:title> <t:title>French I</t:title> <t:title>French II</t:title> //defns //*[local-name()="defns"] <defns xmlns="urn:default">content</defns>
19
PHP and XML PHP 5 introduced numerous interfaces for working with XML
The libxml2 library ( was chosen to provide XML support The sister library libxslt provides XSLT support I/O is handled via PHP streams
20
XML Entensions for PHP 5 ext/libxml ext/xml (SAX push parser) ext/dom
ext/simplexml ext/xmlreader (pull parser) ext/xmlwriter ext/xsl ext/wddx ext/soap
21
Libxml Contains common functionality shared across extensions.
Defines constants to modify parse time behavior. Provides access to streams context. Allows modification of error handling behavior for XML based extensions.
22
Libxml: Parser Options
LIBXML_NOENT Substitute entities with replacement content LIBXML_DTDLOAD Load subsets but do not perform validation LIBXML_DTDATTR Create defaulted attributes defined in DTD LIBXML_DTDVALID Loads subsets and perform validation LIBXML_NOERROR Suppress parsing errors from libxml2 LIBXML_NOWARNING Suppress parser warnings from libxml2 LIBXML_NOBLANKS Remove insignificant whitespace on parsing LIBXML_XINCLUDE Perform XIncludes during parsing LIBXML_NOCDATA Merge CDATA nodes in Text nodes LIBXML_NONET Disable network access when loading
23
Libxml: Error Handling
bool libxml_use_internal_errors ([bool use_errors]) void libxml_clear_errors ( void ) LibXMLError libxml_get_last_error ( void ) array libxml_get_errors ( void )
24
Libxml: LibXMLError Class: LibXMLError LibXMLError::code Values:
Properties (Read-Only): (int) level (int) code (int) column (string) message (string) file (int) line LibXMLError::code Values: LIBXML_ERR_NONE LIBXML_ERR_WARNING LIBXML_ERR_ERROR LIBXML_ERR_FATAL
25
LibXMLError Example libxml/error.php
/* Regular Error Handling */ $dom = new DOMDocument(); $dom->loadXML('<root>'); /* New Error Handling */ libxml_use_internal_errors(TRUE); if (! $dom->loadXML('root')) { $arrError = libxml_get_errors(); foreach ($arrError AS $xmlError) { var_dump($xmlError); } } else { print "Document Loaded"; ?>
26
LibXMLError Result New Error Handling:
PHP Warning: DOMDocument::loadXML(): Premature end of data in tag root line 1 in Entity, line: 1 in /home/rrichards/workshop/libxml/error.php on line 4 Warning: DOMDocument::loadXML(): Premature end of data in tag root line 1 in Entity, line: 1 in /home/rrichards/workshop/libxml/error.php on line 4 New Error Handling: object(LibXMLError)#2 (6) { ["level"]=> int(3) ["code"]=> int(4) ["column"]=> int(1) ["message"]=> string(34) "Start tag expected, '<' not found" ["file"]=> string(0) "" ["line"]=> int(1) }
27
DOM Tree based parser Allows for creation and editing of XML documents
W3C Specification with DOM Level 2/3 compliancy Provides XPath support Provides XInclude Support Ability to work with HTML documents Zero copy interoperability with SimpleXML Replacement for ext/domxml from PHP 4
28
DOMNode Classes DOMDocument DOMElement DOMAttr DOMComment
DOMDocumentType DOMNotation DOMEntity DOMEntityReference DOMProcessingInstruction DOMNameSpaceNode DOMDocumentFragment DOMCharacterData DOMText DOMCdataSection
29
Additional DOM Classes
DOMException DOMImplementation DOMNodeList DOMNamedNodeMap DOMXPath
30
DOM: Sample Document <courses> <course cid="c1">
<title>Basic Languages</title> <description>Introduction to Languages</description> <credits>1.5</credits> <lastmodified> T11:13:01</lastmodified> </course> <course cid="c2"> <title>French I</title> <description>Introduction to French</description> <credits>3.0</credits> <lastmodified> T14:21:37</lastmodified> <course cid="c3"> <title>French II</title> <description>Intermediate French</description> <lastmodified> T15:45:44</lastmodified> </courses>
31
DOM: Document Navigation dom/navigate.php
/* Find first description element in subtrees */ function locateDescription($nodeset) { foreach ($nodeset AS $node) { if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'description') { $GLOBALS['arNodeSet'][] = $node; return; } if ($node->hasChildNodes()) { locateDescription($node->childNodes); } $dom = new DOMDocument(); $dom->load('course.xml'); $root = $dom->documentElement; $arNodeSet = array(); if ($root->hasChildNodes()) { locateDescription($root->childNodes); } foreach ($arNodeSet AS $key=>$node) { print "#$key: ".$node->nodeValue."\n"; }
32
DOM: Document Navigation Results
#0: Introduction to Languages #1: Introduction to French #2: Intermediate French
33
DOM:Document Navigation #2 dom/navigate-2.php
$dom = new DOMDocument(); $dom->load('course.xml'); $nodelist = $dom->getElementsByTagName('description'); foreach ($nodelist AS $key=>$node) { print "#$key: ".$node->nodeValue."\n"; } ?> Results: #0: Introduction to Languages #1: Introduction to French #2: Intermediate French
34
DOM: Navigation Optimized dom/navigate-optimized.php
function locateDescription($node) { while($node) { if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'description') { $GLOBALS['arNodeSet'][] = $node; return; } locateDescription($node->firstChild); $node = $node->nextSibling; $dom = new DOMDocument(); $dom->load('course.xml'); $root = $dom->documentElement; $arNodeSet = array(); locateDescription($root->firstChild); foreach ($arNodeSet AS $key=>$node) { print "#$key: ".$node->nodeValue."\n";
35
DOM: Creating a Simple Tree dom/create_simple_tree.php
$doc = new DOMDocument(); $root = $doc->createElement("tree"); $doc->appendChild($root); $root->setAttribute("att1", "att1 value"); $attr2 = $doc->createAttribute("att2"); $attr2->appendChild($doc->createTextNode("att2 value")); $root->setAttributeNode($attr2); $child = $root->appendChild($doc->createElement("child")); $comment = $doc->createComment("My first Document"); $doc->insertBefore($comment, $root); $pi = $doc->createProcessingInstruction("php", 'echo "Hello World!"'); $root->appendChild($pi); $cdata = $doc->createCdataSection("special chars: & < > '"); $child->appendChild($cdata);
36
DOM: Simple Tree Output
<?xml version="1.0"?> <!--My first Document--> <tree att1="att1 value" att2="att2 value"> <child><![CDATA[special chars: & < > ']]></child> <?php echo "Hello World!"?> </tree>
37
DOM: Creating an Atom Feed dom/atom_feed_creation.php
define('ATOMNS', ' $feed_title = "Example Atom Feed"; $alt_url = " $feed = " $doc = new DOMDocument("1.0", "UTF-8"); function create_append_Atom_elements($doc, $name, $value=NULL, $parent=NULL) { if ($value) $newelem = $doc->createElementNS(ATOMNS, $name, $value); else $newelem = $doc->createElementNS(ATOMNS, $name); if ($parent) { return $parent->appendChild($newelem); } } $feed = create_append_Atom_elements($doc, 'feed', NULL, $doc); create_append_Atom_elements($doc, 'title', $feed_title, $feed); create_append_Atom_elements($doc, 'subtitle', $feed_title, $feed); create_append_Atom_elements($doc, 'id', $alt_url, $feed); create_append_Atom_elements($doc, 'updated', date('c'), $feed); $doc->formatOutput = TRUE; print $doc->saveXML();
38
DOM: Creating an Atom Feed Result (initial structure)
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns=" <title>Example Atom Feed</title> <subtitle>Example Atom Feed</subtitle> <id> <updated> T01:39:40-05:00</updated> </feed>
39
DOM: Creating an Atom Feed dom/atom_feed_creation.php
$entry = create_append_Atom_elements($doc, 'entry', NULL, $feed); $title = create_append_Atom_elements($doc, 'title', 'My first entry', $entry); $title->setAttribute('type', 'text'); $link = create_append_Atom_elements($doc, 'link', NULL, $entry); $link->setAttribute('type', 'text/html'); $link->setAttribute('rel', 'alternate'); $link->setAttribute('href', ' $link->setAttribute('title', 'My first entry'); $author = create_append_Atom_elements($doc, 'author', NULL, $entry); create_append_Atom_elements($doc, 'name', 'Rob', $author); create_append_Atom_elements($doc, 'id', ' $entry); create_append_Atom_elements($doc, 'updated', date('c'), $entry); create_append_Atom_elements($doc, 'published', date('c'), $entry); $content = create_append_Atom_elements($doc, 'content', NULL, $entry); $cdata = $doc->createCDATASection('This is my first Atom entry!<br />More to follow'); $content->appendChild($cdata); $doc->formatOutput = TRUE; print $doc->saveXML();
40
DOM: Creating an Atom Feed Result dom/atomoutput.xml
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns=" <title>Example Atom Feed</title> <subtitle>Example Atom Feed</subtitle> <id> <updated> T01:53:59-05:00</updated> <entry> <title type="text">My first entry</title> <link type="text/html" rel="alternate" href=" title="My first entry"/> <author> <name>Rob</name> </author> <id> <published> T01:53:59-05:00</published> <content><![CDATA[This is my first Atom entry!<br />More to follow]]></content> </entry> </feed>
41
DOM: Document Editing dom/editing.php
$dom->load('atomoutput.xml'); $child = $dom->documentElement->firstChild; while($child && $child->nodeName != "entry") { $child = $child->nextSibling; } if ($child && ($child = $child->firstChild)) { while($child && $child->nodeName != "title") { $child = $child->nextSibling; } if ($child) { $child->setAttribute('type', 'html'); $text = $child->firstChild; $text->nodeValue = "<em>My first entry</em>"; while($child) { if ($child->nodeName == "updated") { $text->nodeValue = date('c'); break; } $child = $child->nextSibling; print $dom->saveXML();
42
DOM: Editing dom/new_atomoutput.xml
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns=" <title>Example Atom Feed</title> <subtitle>Example Atom Feed</subtitle> <id> <updated> T01:53:59-05:00</updated> <entry> <title type="html"><em>My first entry</em></title> <link type="text/html" rel="alternate" href=" title="My first entry"/> <author> <name>Rob</name> </author> <id> <updated> T02:29:22-05:00</updated> <published> T01:53:59-05:00</published> <content><![CDATA[This is my first Atom entry!<br />More to follow]]></content> </entry> </feed>
43
DOM: Document Modification dom/modify.php
/* Assume $entry refers to the first entry element within the Atom document */ while ($entry->hasChildNodes()) { $entry->removeChild($entry->firstChild); } OR $node = $entry->lastChild; while($node) { $prev = $node->previousSibling; $entry->removeChild($node); $node = $prev; /* This Will Not Work! */ foreach($entry->childNodes AS $node) { /* These will work */ $children = $entry->childNodes; $length = $children->length - 1; for ($x=$length; $x >=0; $x--) { $entry->removeChild($children->item($x)); } OR $elem = $entry->cloneNode(FALSE); $entry->parentNode->replaceChild($elem, $entry);
44
DOM and Namespaces <xsd:complexType
xmlns:xsd=" xmlns:wsdl=" name="ArrayOfint"> <xsd:complexContent> <xsd:restriction base="soapenc:Array"> <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[ ]"/> </xsd:restriction> </xsd:complexContent> </xsd:complexType>
45
Dom and Namepsaces dom/namespace.php
define("SCHEMA_NS", " define("WSDL_NS", " $dom = new DOMDocument(); $root = $dom->createElementNS(SCHEMA_NS, "xsd:complexType"); $dom->appendChild($root); $root->setAttributeNS(" "xmlns:wsdl", WSDL_NS); $root->setAttribute("name", "ArrayOfint"); $content = $root->appendChild(new DOMElement("xsd:complexContent", NULL, SCHEMA_NS)); $restriction = $content->appendChild(new DOMElement("xsd:restriction", NULL, SCHEMA_NS)); $restriction->setAttribute("base", "soapenc:Array"); $attribute = $restriction->appendChild(new DOMElement("xsd:attribute", NULL, SCHEMA_NS)); $attribute->setAttribute("ref", "soapenc:arrayType"); $attribute->setAttributeNS(WSDL_NS, "wsdl:arrayType", "xsd:int[]");
46
DOM and Xpath dom/xpath/dom-xpath.xml
<store> <books> <rare> <book qty="4"> <name>Cannery Row</name> <price>400.00</price> <edition>1</edition> </book> </rare> <classics> <book qty="25"> <name>Grapes of Wrath</name> <price>12.99</price> <name>Of Mice and Men</name> <price>9.99</price> </classics> </books> </store>
47
DOM and Xpath dom/xpath/dom-xpath.php
$doc = new DOMDocument(); $doc->load('dom-xpath.xml'); $xpath = new DOMXPath($doc); $nodelist = $xpath->query("//name"); print "Last Book Title: ".$nodelist->item($nodelist->length - 1)->textContent."\n"; $nodelist = $xpath->query("//name[ancestor::rare]"); print "Last Rare Book Title: ".$nodelist->item($nodelist->length - 1)->nodeValue."\n"; $inventory = print "Total Books: ".$inventory."\n"; $inventory = print "Total Classic Books: ".$inventory."\n"; $inventory = $xpath->evaluate("count(//book[parent::classics])"); print "Distinct Classic Book Titles: ".$inventory."\n";
48
DOM and Xpath Results Last Book Title: Of Mice and Men
/* $nodelist = $xpath->query("//name") $nodelist->item($nodelist->length - 1)->textContent */ Last Book Title: Of Mice and Men /* $xpath->query("//name[ancestor::rare]"); $nodelist->item($nodelist->length - 1)->nodeValue */ Last Rare Book Title: Cannery Row /* */ Total Books: 54 /* */ Total Classic Books: 50 /* $xpath->evaluate("count(//book[parent::classics])") */ Distinct Classic Book Titles: 2
49
DOM and Xpath w/Namespaces dom/xpath/dom-xpathns.xml
<store xmlns=" xmlns:bk=" <books> <rare> <bk:book qty="4"> <bk:name>Cannery Row</bk:name> <bk:price>400.00</bk:price> <bk:edition>1</bk:edition> </bk:book> </rare> <classics> <bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price> <bk:book qty="25" xmlns:bk=" <bk:name>Of Mice and Men</bk:name> <bk:price>9.99</bk:price> </classics> <classics xmlns=" <book qty="33"> <name>To Kill a Mockingbird</name> <price>10.99</price> </book> </books> </store>
50
DOM and Xpath w/Namespaces dom/xpath/dom-xpathns.php
$nodelist = $xpath->query("//name"); print "Last Book Title: ".$nodelist->item($nodelist->length - 1)->textContent."\n"; // Last Book Title: /* Why empty? */ $nodelist = $xpath->query("//bk:name"); // Last Book Title: Grapes of Wrath /* Why not "Of Mice and Men" */ $nodelist = $xpath->query("//bk:name[ancestor::rare]"); print "Last Rare Book Title: ".$nodelist->item($nodelist->length - 1)->nodeValue."\n"; // Last Rare Book Title: /* Why empty? */ $xpath->registerNamespace("rt", " $nodelist = $xpath->query("//bk:name[ancestor::rt:rare]"); // Last Rare Book Title: Cannery Row $xpath->registerNamespace("ext", " $nodelist = $xpath->query("(//bk:name) | (//ext:name)"); // Last Book Title: To Kill a Mockingbird
51
DOM and Xpath w/Namespaces dom/xpath/dom-xpathns.php
$xpath->registerNamespace("bk2", " $nodelist = $xpath->query("//bk2:name"); print "Last Book Title (bk2): " print $nodelist->item($nodelist->length - 1)->textContent."\n"; // Last Book Title (bk2): Of Mice and Men Complete Results: Last Book Title: Last Book Title: Grapes of Wrath Last Rare Book Title: Last Rare Book Title: Cannery Row Last Book Title: To Kill a Mockingbird Last Book Title (bk2): Of Mice and Men
52
Performing Validation dom/validation/validate.php
$doc = new DOMDocument(); print "DTD Validation:\n"; $doc->load('courses-dtd.xml', LIBXML_DTDVALID); /* No errors means document is valid */ if ($doc->validate()) { print " Document Is Valid\n"; } print "DTD Validation FAILURE:\n"; $doc->load('course-id.xml'); if ($doc->validate()) { print " Document Is Valid\n"; } $doc->load('course.xml'); print "\nXML Schema Validation:\n"; if ($doc->schemaValidate('course.xsd')) { print " Document is valid\n"; } print "\nRelaxNG Validation:\n"; if ($doc->relaxNGValidate('course.rng')) { print " Document is valid\n"; }
53
Performing Validation Results
DTD Validation: Document Is Valid DTD Validation FAILURE: Warning: DOMDocument::validate(): No declaration for element courses in /home/rrichards/workshop/dom/validation/validate.php on line 11 Warning: DOMDocument::validate(): No declaration for element course in /home/rrichards/workshop/dom/validation/validate.php on line 11 Warning: DOMDocument::validate(): No declaration for element title in /home/rrichards/workshop/dom/validation/validate.php on line 11 . . . XML Schema Validation: Document is valid RelaxNG Validation:
54
Extending DOM Classes Overriding the constructor requires the parent constructor to be called. Properties built into the DOM classes cannot be overridden. Methods built into the DOM classes may can be overridden. The lifespan of an extended object is that of the object itself.
55
Extending DOM Classes dom/extending/extending.php
class customElement extends DOMElement { } class customDoc extends DOMDocument { public $nodeName = "customDoc"; function __construct($rootName) { parent::__construct(); if (! empty($rootName)) { $element = $this->appendChild(new DOMElement($rootName)); } } function createElement($name, $value, $parent=NULL) { $custom = new customElement($name, $value); if ($parent && ($parent instanceof DOMElement)) { $parent->appendChild($custom); } return $custom; $myc = new customDoc("root"); $myelement = $myc->createElement("myname", "myvalue", $myc->documentElement); if ($myelement instanceof customElement) { print "This is a customElement\n"; } print $myc->nodeName."\n"; print $myc->saveXML();
56
DOM Object Scope dom/extending/object_scope.php
class customElement extends DOMElement { } function changeit($doc) { $myelement = new customElement("custom", "element2"); $doc->replaceChild($myelement, $doc->documentElement); print "Within changeit function: ".get_class($doc->documentElement)."\n"; } $doc = new DOMDocument(); $myelement = $doc->appendChild(new customElement("custom", "element")); print "After Append: ".get_class($myelement)."\n"; unset($myelement); print "After unset: ".get_class($doc->documentElement)."\n"; changeit($doc); print "Outside changeit(): ".get_class($doc->documentElement)."\n"; After Append: customElement After unset: DOMElement Within changeit function: customElement Outside changeit(): DOMElement
57
DOM: registerNodeClass dom/extending/register_node_class.php
class customElement extends DOMElement { } function changeit($doc) { $myelement = new DOMElement("custom", "element2"); $doc->replaceChild($myelement, $doc->documentElement); print "Within changeit function: ".get_class($doc->documentElement)."\n"; } $doc = new DOMDocument(); $doc->registerNodeClass('DOMElement', 'customElement'); $myelement = $doc->appendChild($doc->createElement("custom", "element")); print "After Append: ".get_class($myelement)."\n"; unset($myelement); print "After unset: ".get_class($doc->documentElement)."\n"; changeit($doc); print "Outside changeit(): ".get_class($doc->documentElement)."\n"; After Append: customElement After unset: customElement Within changeit function: DOMElement Outside changeit(): customElement
58
DOM:Common Issues DOM Objects and Sessions
Removing Nodes while iterating a Nodeset skips nodes XML Tree contains garbled characters Extended class is not returned from property or method Elements not being returned by ID Entity errors are issues when loading a document New DTD is not recognized by document
59
SimpleXML Provides simple access to XML documents
Operates only on elements and attributes Contains XPath support Allows for modifications to the XML Zero copy interoperability with DOM New in PHP 5.1.3 Elements and attributes can be added using addChild() and addAttribute() methods. Node names can be retrieved by calling getName().
60
SimpleXML: Consuming Yahoo WebSearch simplexml/yahoo_rest_results.xml
<ResultSet xmlns:xsi=" xmlns="urn:yahoo:srch" xsi:schemaLocation="urn:yahoo:srch totalResultsAvailable="374000" totalResultsReturned="5" firstResultPosition="1"> <Result> <Title>Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New?</Title> <Summary>XML in PHP 5 - What's New? By Christian Stocker. March </Summary> <Url> <ClickUrl> . .</ClickUrl> <ModificationDate> </ModificationDate> <MimeType>text/html</MimeType> <Cache> <Url> <Size>112625</Size> </Cache> </Result> . . . </Results>
61
SimpleXML: Consuming Yahoo WebSearch simplexml/reading_rest.php
/* URL to Web Search service */ $url = ' /* The query is separate here as the terms must be encoded. */ $url .= '?query='.rawurlencode('php5 xml'); /* Complete the URL adding App ID, limit to 5 results and only English results */ $url .= "&appid=zzz&results=5&language=en"; $sxe = simplexml_load_file($url); /* Check for number of results returned */ if ((int)$sxe['totalResultsReturned'] > 0) { /* Loop through each result and output title, url and modification date */ foreach ($sxe->Result AS $result) { print 'Title: '.$result->Title."\n"; print 'Url: '.$result->Url."\n"; print 'Mod Date: '.date ('M d Y', (int)$result->ModificationDate)."\n\n"; }
62
SimpleXML: Consuming Yahoo WebSearch RESULTS
Title: Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New? Url: Mod Date: Sep Title: FreshPorts -- textproc/php5-xml Url: Mod Date: Aug Title: PHP5 XML support? - Dev Shed Url: Mod Date: Aug Title: ONLamp.com -- Using PHP 5's SimpleXML Url: Title: PHP5 XML/XSL - Rendering strings? - PHP Url: Mod Date: Sep
63
<store xmlns="http://www. example. com/store" xmlns:bk="http://www
<store xmlns=" xmlns:bk=" <books> <rare> <bk:book qty="4"> <bk:name>Cannery Row</bk:name> <bk:price>400.00</bk:price><bk:edition>1</bk:edition> </bk:book> </rare> <classics> <bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price> <bk:book qty="25" xmlns:bk=" <bk:name>Of Mice and Men</bk:name> <bk:price>9.99</bk:price> </classics> <classics xmlns=" <book qty="33"> <name>To Kill a Mockingbird</name> <price>10.99</price> </book> </books> </store>
64
SimpleXML: Namespaces simplexml/simplexml-namespace.php
$store = simplexml_load_file('simplexml-xpathns.xml'); $books = $store->books; foreach ($books->classics AS $classic) { if ($classic->book) print $classic->book->name."\n\n"; } /* Why only one result?: To Kill a Mockingbird */ $x = 0; foreach ($books->classics AS $classics) { if ($x++ == 0) { $children = $classics->children(" /* Print name for the books where book element resides in a prefixed namespace */ print $classics->children(" print $children->book->name."\n"; } else print $classic->book->name."\n";
65
SimpleXML: Namespaces Results
To Kill a Mockingbird Grapes of Wrath Of Mice and Men
66
SimpleXML: Xpath simplexml/simplexml-xpathns.php
$sxe = simplexml_load_file('simplexml-xpathns.xml'); $nodelist = $sxe->xpath("//bk:name"); print "Last Book Title: ".$nodelist[count($nodelist) - 1]."\n"; $sxe->registerXPathNamespace("rt", " $nodelist = $sxe->xpath("//bk:name[ancestor::rt:rare]"); print "Last Rare Book Title: ".$nodelist[count($nodelist) - 1]."\n"; $sxe->registerXPathNamespace("ext", " $nodelist = $sxe->xpath("(//bk:name) | (//ext:name)"); $sxe->registerXPathNamespace("bk2", " $nodelist = $sxe->xpath("//bk2:name"); print "Last Book Title (bk2): ".$nodelist[count($nodelist) - 1]."\n";
67
SimpleXML: XPath Results
Last Book Title: Grapes of Wrath Last Rare Book Title: Cannery Row Last Book Title: To Kill a Mockingbird Last Book Title (bk2): Of Mice and Men
68
SimpleXML: Advanced Editing simplexml/editing.php
$data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'), array('title'=>'Result 2', 'descript'=>'description of Res2'), array('title'=>'Result 3', 'descript'=>'This is result 3')); class webservice extends simpleXMLElement { public function appendElement($name, $value=NULL) { $node = dom_import_simplexml($this); $newnode = $value ? new DOMElement($name, $value) : new DOMElement($name); $node->appendChild($newnode); return simplexml_import_dom($newnode, 'webservice'); } } $rest = simplexml_load_string('<results num="0" />', 'webservice'); $rest['num'] = count($data); foreach ($data AS $result_item) { $result = $rest->appendElement('result'); $result->appendElement('title', $result_item['title']); $result->appendElement('description'); $result->description = $result_item['descript']; } print $rest->asXML();
69
SimpleXML: Advanced Editing Results
<?xml version="1.0"?> <results num="3"> <result> <title>Result 1</title> <description>Res1 description</description> </result> <title>Result 2</title> <description>description of Res2</description> <title>Result 3</title> <description>This is result 3</description> </results>
70
SimpleXML: Advanced Editing PHP 5.1.3 simplexml/editing_php513.php
$data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'), array('title'=>'Result 2', 'descript'=>'description of Res2'), array('title'=>'Result 3', 'descript'=>'This is result 3')); $rest = simplexml_load_string('<results num="0" />'); $rest['num'] = count($data); foreach ($data AS $result_item) { $result = $rest->addChild('result'); $result->addChild('title', $result_item['title']); $result->addChild('description'); $result->description = $result_item['descript']; } $rest->asXML('editing_php513.xml');
71
SimpleXML: Removing data remove_data.php
$results = simplexml_load_file('editing_php513.xml'); /* Delete title from first result element */ unset($results->result->title); /* Delete the 2nd result element - ONLY WORKS in PHP */ unset($results->result[1]); print $results->asXML(); ?>
72
SimpleXML: Removing data RESULTS
<?xml version="1.0"?> <results num="3"> <result> <description>Res1 description</description> </result> <title>Result 3</title> <description>This is result 3</description> </results>
73
Simple API for XML (SAX)
Event based push parser Low memory usage Works using function callbacks Almost completely compatible with ext/xml from PHP 4 Default encoding is UTF-8 rather than ISO as it was in PHP 4
74
SAX: Source Document xml/xml_simple.xml
<?xml version='1.0'?> <chapter xmlns:a=" xmlns=" <a:title>ext/xml</a:title> <para> First Paragraph </para> <a:section a:id="about"> <title>About this Document</title> <!-- this is a comment --> <?php echo 'Hi! This is PHP version ' . phpversion(); ?> </a:section> </chapter>
75
SAX: Simple Example xml/xml_simple.php
function startElement($parser, $elementname, $attributes) { print "* Start Element: $elementname \n"; foreach ($attributes as $attname => $attvalue) { print " $attname => $attvalue \n"; } function endElement($parser, $elementname) { print "* End Element: $elementname\n"; function charDataHandler($parser,$data) { if (trim($data) != "") print $data."\n"; function PIhandler ($parser, $target, $data) { print "PI: $target -> $data\n"; function DefaultHandler($parser, $data) { print "Default: $data\n";
76
SAX: Simple Example xml/xml_simple.php
$parser = xml_parser_create(); /* Disable as case is significant in XML */ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false); xml_set_element_handler($parser,"startElement","endElement"); xml_set_character_data_handler($parser, "charDataHandler"); xml_set_processing_instruction_handler ($parser, "PIhandler"); xml_set_default_handler ($parser, "DefaultHandler"); if (($fp = fopen("xml_simple.xml", "r"))) { while ($data = fread($fp, 4096)) { xml_parse($parser, $data, feof($fp)); } ?>
77
SAX: Simple Example RESULTS
* Start Element: chapter xmlns:a => xmlns => * Start Element: a:title ext/xml * End Element: a:title * Start Element: para First Paragraph * End Element: para * Start Element: a:section a:id => about * Start Element: title About this Document * End Element: title Default: <!-- this is a comment --> PI: php -> echo 'Hi! This is PHP version ' . phpversion(); * End Element: a:section * End Element: chapter
78
SAX: Error Handling xml/xml_error.php
/* Malformed document */ $data = "<root>"; $parser = xml_parser_create(); if(! xml_parse($parser, $data, TRUE)) { /* Normally die is or some other escape mechanism is also called*/ printf("XML error: %s in line %d, column %d\n\n", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser), xml_get_current_column_number($parser)); } /* Magically you can also get a structured error */ $xmlError = libxml_get_last_error(); var_dump($xmlError); ?>
79
SAX: Error Handling RESULTS
XML error: Invalid document end in line 1, column 7 object(LibXMLError)#1 (6) { ["level"]=> int(3) ["code"]=> int(5) ["column"]=> int(7) ["message"]=> string(41) "Extra content at the end of the document " ["file"]=> string(0) "" ["line"]=> int(1) }
80
SAX: Advanced Example xml/xml_advanced.php
class cSax { function startElement($parser, $elementname, $attributes) { list($namespaceURI,$localName)= if (! $localName) { $localName = $namespaceURI; $namespaceURI = ""; } print "* Start Element: $localName". ($namespaceURI ? " in $namespaceURI" : "")."\n"; foreach ($attributes as $attname => $attvalue) { print " $attname => $attvalue \n"; function endElement($parser, $elementname) { print "* End Element: $localName".
81
SAX: Advanced Example xml/xml_advanced.php
$objcSax = new cSax(); $parser = /* Disable as case is significant in XML */ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false); xml_set_object($parser, $objcSax); xml_set_element_handler($parser,"startElement","endElement"); if (($fp = fopen("xml_simple.xml", "r"))) { while ($data = fread($fp, 4096)) { if (! xml_parse($parser, $data, feof($fp))) { $xmlError = libxml_get_last_error(); var_dump($xmlError); exit; }
82
SAX: Advanced Example RESULTS
* Start Element: chapter in * Start Element: title in * End Element: title in * Start Element: para in * End Element: para in * Start Element: section in => about * Start Element: title in * End Element: title in * End Element: section in * End Element: chapter in
83
XMLReader Forward moving stream based parser It is a Pull parser
Based on the C# XmlTextReader API Advantages: Low memory footprint Namespace support Simple API Validation support Advanced Feature Set Faster Processing
84
XMLReader: Simple Example xmlreader/reader_simple.xml
<?xml version='1.0'?> <chapter xmlns:a=" xmlns=" <a:title>XMLReader</a:title> <para> First Paragraph </para> <a:section a:id="about"> <title>About this Document</title> <!-- this is a comment --> <?php echo 'Hi! This is PHP version ' . phpversion(); ?> </a:section> </chapter>
85
XMLReader: Simple Example xmlreader/reader_simple.php
$reader = new XMLReader(); $reader->open('reader_simple.xml'); $reader->read(); print "xmlns Attribute value: ".$reader->getAttributeNo(0)."\n\n"; while ($reader->read() && $reader->name != "a:title") { } print "Local Name for Element: ".$reader->localName."\n"; print "Namespace URI for Element: ".$reader->namespaceURI."\n"; while($reader->read()) { switch ($reader->nodeType) { case XMLReader::ELEMENT: print "Element: ".$reader->name."\n"; if ($reader->hasAttributes && $reader->moveToFirstAttribute()) { do { print " ".$reader->name."=".$reader->value."\n"; } while($reader->moveToNextAttribute()); } break; case XMLReader::PI: print "PI Target: ".$reader->name."\n PI Data: ".$reader->value."\n";
86
XMLReader: Simple Example RESULTS
Local Name for Element: title Namespace URI for Element: Element: para Element: a:section a:id=about Element: title PI Target: php PI Data: echo 'Hi! This is PHP version ' . phpversion();
87
XMLReader: Consuming Yahoo Shopping
<?xml version="1.0" encoding="ISO "?> <ResultSet xmlns:xsi=" xmlns="urn:yahoo:prods" xsi:schemaLocation="urn:yahoo:prods totalResultsAvailable="8850" firstResultPosition="2" totalResultsReturned="2"> <Result> <Catalog ID=" "> <Url><![CDATA[ . .2]]></Url> <ProductName><![CDATA[Linksys WRT5. . .r Broadband Router]]></ProductName> <PriceFrom>59.99</PriceFrom> <PriceTo>100.00</PriceTo> <Thumbnail /><!-- child elements Url (CDATA), Height, Width --> <Description><![CDATA[The Wireless-G . . .ces.]]></Description> <Summary><![CDATA[IEEE 802.3, ...]]></Summary> <UserRating /><!-- Rating sub elements --> <SpecificationList /><!-- 0+ Specification child elements --> </SpecificationList> </Catalog> </Result> </ResultSet>
88
XMLReader: Consuming Yahoo Shopping xmlreader/rest_yahoo_shopping.php
function getTextValue($reader) { ... } function processCatalog($reader) { ... } function processResult($reader) { ... } /* URL to Product Search service */ $url = ' /* The query is separate here as the terms must be encoded. */ $url .= '?query='.rawurlencode('linksys'); /* Complete the URL with App ID, limit to 1 result and start at second record */ $url .= "&appid=zzz&results=2&start=2"; $reader = new XMLReader(); if (! $reader->open($url)) { print "Cannot access Webservice\n"; exit; } while($reader->name != "Result") { $reader->read(); } do { processResult($reader); } while($reader->next('Result'));
89
XMLReader: Consuming Yahoo Shopping xmlreader/rest_yahoo_shopping.php
function getTextValue($reader) { if ($reader->nodeType != XMLReader::ELEMENT || $reader->isEmptyElement || ($reader->read() && $reader->nodeType == XMLReader::END_ELEMENT)) return; $retVal = $reader->value; $reader->read(); return $retVal; } function processResult($reader) { $depth = $reader->depth; if ($reader->isEmptyElement || ($reader->read() && $reader->nodeType == XMLReader::END_ELEMENT)) while($depth < $reader->depth && $reader->name != "Catalog") { $reader->read(); }; processCatalog($reader); /* Read until </Result> is encountered */ while($depth < $reader->depth) { $reader->read(); }
90
XMLReader: Consuming Yahoo Shopping xmlreader/rest_yahoo_shopping.php
function processCatalog($reader) { $depth = $reader->depth; print "Catalog ID".$reader->getAttribute('ID')."\n"; if ($reader->isEmptyElement || ($reader->read() && $reader->nodeType == XMLReader::END_ELEMENT)) return; while($depth < $reader->depth) { switch ($reader->name) { case "ProductName": case "PriceFrom": case "PriceTo": case "Description": case "Url": print $reader->name.": ".getTextValue($reader)."\n"; } $reader->next();
91
XMLReader: Consuming Yahoo Shopping RESULTS (Abbreviated)
Catalog ID Url: ProductName: Linksys Instant Broadband EtherFast Cable/DSL Router PriceFrom: 39.99 PriceTo: 72.71 Description: <P>Linksys, a provider of networking hardware for the small/medium business (SMB), small office/home office (SOHO), and enterprise markets and broadband networking hardware for the home, has announced the new EtherFast Cable/DSL Router. The first in the new Instant Broadband series, this Linksys broadband router will enable home or office users to connect their computers to a cable or DSL modem and securely share Internet access and perform networking tasks such as file and printer sharing. The built-in hardware firewall gives users the security of sharing files without fear of intruders hacking into the network. </P>
92
XMLReader: DTD Validation xmlreader/validation/reader.xml
<!DOCTYPE chapter [ <!ELEMENT chapter (title, para, section)> <!ELEMENT title (#PCDATA)> <!ELEMENT para ANY> <!ATTLIST para name CDATA "default"> <!ELEMENT section (#PCDATA)> <!ATTLIST section id ID #REQUIRED> ]> <chapter> <title>XMLReader</title> <para> First Paragraph </para> <section id="about"> <title>About this Document</title> <para>content</para> </section> </chapter>
93
XMLReader: DTD Validation xmlreader/validation/reader.php
$objReader = XMLReader::open('reader.xml'); $objReader->setParserProperty(XMLReader::VALIDATE, TRUE); /* As of PHP 5.2 LIBXML Parser Options may be passed */ // $objReader = XMLReader::open('reader.xml', NULL, LIBXML_DTDVALID); libxml_use_internal_errors(TRUE); while ($objReader->read()) { if (! $objReader->isValid()) { print "NOT VALID\n"; break; } $arErrors = libxml_get_errors(); foreach ($arErrors AS $xmlError) { print $xmlError->message;
94
XMLReader: DTD Validation RESULTS
NOT VALID Element section was declared #PCDATA but contains non text nodes
95
XMLReader: Relax NG Validation xmlreader/validation/reader.rng
<?xml version="1.0" encoding="utf-8" ?> <element name="chapter" xmlns=" <element name="title"> <text/> </element> <element name="para"> <element name="section"> <attribute name="id" />
96
XMLReader: Relax NG Validation xmlreader/validation/reader-rng.php
$objReader = XMLReader::open('reader.xml'); $objReader->setRelaxNGSchema('reader.rng'); libxml_use_internal_errors(TRUE); while ($objReader->read()) { if (! $objReader->isValid()) { print "NOT VALID\n"; break; } $arErrors = libxml_get_errors(); foreach ($arErrors AS $xmlError) { print $xmlError->message;
97
XMLReader: Relax NG Validation RESULTS
NOT VALID Did not expect element title there
98
XSL Used to transform XML data XSLT based on XPath
Works with DOM and SimpleXML, although the DOM extension is required. Provides the capability of calling PHP functions during a transformation DOM nodes may be returned from PHP functions The LIBXML_NOCDATA and LIBXML_NOENT constants are your friends. libxslt is recommended to avoid problems when using xsl:key
99
XSL: XML Input Data xsl/sites.xml
<?xml version="1.0"?> <sites> <site xml:id="php-gen"> <name>PHP General</name> <url> </site> <site xml:id="php-pear"> <name>PHP Pear Dev</name> <url> <site xml:id="php-planet"> <name>Planet PHP</name> <url> </sites>
100
XSL: Simple Transformation xsl/simple_stylesheet.xsl
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <html> <body> <xsl:apply-templates select="/sites/site"/> </body> </html> </xsl:template> <xsl:template match="/sites/site"> <p><xsl:value-of select="./name"/> : <xsl:value-of select="./url" disable-output-escaping="yes"/></p> </xsl:stylesheet>
101
XSL: Simple Transformation xsl/simple_stylesheet.php
/* Load Stylesheet */ $stylesheet = new DOMDocument(); $stylesheet->load('simple_stylesheet.xsl'); /* Create XSL Processor */ $proc = new xsltprocessor(); $proc->importStylesheet($stylesheet); /* Load XML Data */ $dom = new DOMDocument(); $dom->load('sites.xml'); print $proc->transformToXML($dom);
102
XSL: Simple Transformation RESULTS
<html> <body> <p>PHP General : <p>PHP Pear Dev : <p>Planet PHP : </body> </html>
103
XSL: Advanced Transformation xsl/advanced_stylesheet.php
function initReader($url) { $GLOBALS['reader'] = new XMLReader(); if ($GLOBALS['reader']->open($url)) { while ($GLOBALS['reader']->read() && $GLOBALS['reader']->name != 'item') { } if ($GLOBALS['reader']->name == 'item') return 1; } $GLOBALS['reader'] = NULL; return 0; function readNextItem() { if ($GLOBALS['reader'] == NULL) return NULL; if ($GLOBALS['beingProc']) $GLOBALS['reader']->next('item'); else $GLOBALS['beingProc'] = TRUE; return $GLOBALS['reader']->expand();
104
XSL: Advanced Transformation xsl/advanced_stylesheet.php
$beingProc = FALSE; $reader = NULL; /* Load Stylesheet */ $stylesheet = new DOMDocument(); $stylesheet->load('advanced_stylesheet.xsl'); /* Create XSL Processor */ $proc = new xsltprocessor(); $proc->importStylesheet($stylesheet); /* Load XML Data */ $dom = new DOMDocument(); $dom->load('sites.xml'); $proc->setParameter(NULL, 'siteid', 'php-gen'); $proc->registerPHPFunctions('initReader'); $proc->registerPHPFunctions('readNextItem'); print $proc->transformToXML($dom); /* END */
105
XSL: Advanced Transformation xsl/advanced_stylesheet.xsl
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=" xmlns:php=" version="1.0"> <xsl:output method="html"/> <xsl:param name="siteid" select="0" /> <xsl:template match="/"> <html><body> <xsl:apply-templates select="id($siteid)"/> </body></html> </xsl:template> <xsl:template match="/sites/site"> <xsl:variable name="itemnum" select="php:functionString('initReader', ./url)" /> <xsl:if test="number($itemnum) > 0"> <xsl:call-template name="itemproc" /> </xsl:if>
106
XSL: Advanced Transformation xsl/advanced_stylesheet.xsl
<xsl:template match="item"> <p> Title: <b><xsl:value-of select="./title" /></b><br/><br/> URL: <xsl:value-of select="./link" /><br/> Published: <xsl:value-of select="./pubDate" /><br/> </p> </xsl:template> <xsl:template name="itemproc"> <xsl:variable name="nodeset" select="php:functionString('readNextItem')" /> <xsl:if test="boolean($nodeset)"> <xsl:apply-templates select="$nodeset"/> <xsl:call-template name="itemproc" /> </xsl:if> </xsl:stylesheet>
107
XSL: Advanced Transformation Results viewed through a browser xsl/advanced_stylesheet.html
Title: Re: Spreadsheet Writer URL: Published: Thu, 07 Sep :52:09 –0400 URL: Published: Thu, 07 Sep :52: URL:
108
XMLWriter Lightweight and forward-only API for generating well formed XML Automatically escapes data Works with PHP 4.3+ available at Object Oriented API available for PHP 5+ Part of core PHP distribution since PHP 5.1.2
109
XMLWriter: Simple Example xmlwriter/simple.php
$xw = new XMLWriter(); $xw->openMemory(); /* Turn on indenting to make output look pretty and set string used for indenting as teh default space is too short*/ $xw->setIndent(TRUE); $xw->setIndentString(' '); /* Write out the optional XML declaration only specifying version */ $xw->startDocument('1.0'); /* Create the opening document element, which is namespaced */ $xw->startElementNs(NULL, "chapter", " /* Write out an xml namespace declaration that is used later in the document */ $res = $xw->writeAttribute('xmlns:a', ' /* Write complete elements with text content */ $xw->writeElement('a:title', 'XMLReader'); $xw->writeElement('para', 'spec chars < > & " inside para element');
110
XMLWriter: Simple Example xmlwriter/simple.php
/* start an element and add an attribute to it */ $xw->startElement('a:section'); $xw->writeAttribute('a:id', 'about'); /* Write out an element with special characters */ $xw->writeElement('title', 'Pro PHP XML & Webservices'); $xw->startElement('para'); /* This opens the para element */ $xw->writeComment("this is a comment"); $xw->text(" "); $xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); "); $xw->text("\n "); $xw->endElement(); /* This will close the open para element */ $xw->endDocument(); /* Flush and clear the buffer */ echo $xw->flush(true); ?>
111
XMLWriter: Simple Example xmlwriter/simple.php
/* start an element and add an attribute to it */ $xw->startElement('a:section'); $xw->writeAttribute('a:id', 'about'); /* Write out an element with special characters */ $xw->writeElement('title', 'Pro PHP XML & Webservices'); $xw->startElement('para'); /* This opens the para element */ $xw->writeComment("this is a comment"); $xw->text(" "); $xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); "); $xw->text("\n "); $xw->endElement(); /* This will close the open para element */ $xw->endDocument(); /* Flush and clear the buffer */ echo $xw->flush(true); ?>
112
XMLWriter: Creating a Rest Service xmlwriter/rest
XMLWriter: Creating a Rest Service xmlwriter/rest.php (startid and maxid) <?php /* If the database does not exist, then create it and populate it with some data */ if (! file_exists('xmlwriterdb')) { if ($dbhandle = sqlite_open('xmlwriterdb', 0666)) { sqlite_query($dbhandle, 'CREATE TABLE xmlwriter (id int, name varchar(15))'); for ($x=1; $x< 11; $x++) { sqlite_query($dbhandle, "INSERT INTO xmlwriter VALUES (".$x.", 'Data Num: ".$x."')"); } sqlite_close($dbhandle); } } /* closes function and saves display space */ /* Retrieve record based on id(s) */ function getDBData($min, $max) { $results = NULL; if ($dbhandle = sqlite_open('xmlwriterdb')) { $strSQL = 'SELECT id, name FROM xmlwriter where id>='.$min.' and id <='.$max; $query = sqlite_query($dbhandle,$strSQL); return sqlite_fetch_all($query, SQLITE_ASSOC); } } /* closes function and saves display space */
113
XMLWriter: Creating a Rest Service xmlwriter/rest.php
/* Setup defaults */ $recid = 0; $minid = 0; $maxid = 0; /* Retrieve requested record id(s) and insure $maxid is never less than $minid */ if (! empty($_GET['startid'])) { $minid = (int) $_GET['startid']; $maxid = $minid; if (! empty($_GET['maxid'])) { $maxid = (int) $_GET['maxid']; if ($minid > $maxid) $maxid = $minid; } /* Retrieve the requested records from the database */ $arResults = getDBData($minid, $maxid);
114
XMLWriter: Creating a Rest Service xmlwriter/rest.php
/* Process the resulting records if any */ header('Content-Type: text/xml'); $xw = new XMLWriter(); /* Send the XML document directly to output as it is written */ $xw->openUri('php://output'); $xw->startDocument('1.0', 'UTF-8'); $xw->startElement('Results'); foreach ($arResults AS $result) { $xw->startElement('Result'); foreach ($result AS $field_name => $field_value) { $xw->writeElement($field_name, $field_value); } $xw->endElement(); /* Progressively send the output */ $xw->flush(); $xw->endDocument(); /* Flush and clear the buffer */
115
XMLWriter: Creating a Rest Service xmlwriter/rest.php
/* Process the resulting records if any */ header('Content-Type: text/xml'); $xw = new XMLWriter(); /* Send the XML document directly to output as it is written */ $xw->openUri('php://output'); $xw->startDocument('1.0', 'UTF-8'); $xw->startElement('Results'); foreach ($arResults AS $result) { $xw->startElement('Result'); foreach ($result AS $field_name => $field_value) { $xw->writeElement($field_name, $field_value); } $xw->endElement(); /* Progressively send the output */ $xw->flush(); $xw->endDocument(); /* Flush and clear the buffer */
116
Tree Parsers Pros: Cons:
Full navigation and modification of the XML document Navigating and searching are extremely fast once the tree is loaded into memory Cons: Must wait until entire tree is loaded to begin working with the XML. Memory intensive
117
Streaming Parsers Pros: Cons: Uses minimal memory
Processing takes place immediately while the document is parsed Cons: Minimal to no navigation support (forward only) No document editing capabilities
118
Raw Test Data Memory Usage: DOM SimpleXML ext/xml XMLReader 85.6MB
<books> <book id="1"><title>1</title><pages>1</pages></book> <book id="2"><title>2</title><pages>2</pages></book> <!-- Remaining book elements for a total of 200,000 --> </books> Memory Usage: DOM SimpleXML ext/xml XMLReader 85.6MB 26KB 177KB Using every optimization possible the following results show the time in seconds to locate the book element having id="5000". Average Time in Seconds for Optimized Search for an Element: DOM SimpleXML ext/xml XMLReader 6.623 6.583 0.930 0.238
119
SOAP An XML-based protocol for exchanging information between applications It allows for remote invocation of methods in a distributed environment Uses existing transport protocols such as HTTP Can operate with or without a Web Service Definition Language (WSDL) document A W3C standard and the core component to the Web Services Interoperability Organization (WS-I) Basic Profile
120
SOAP: Basic WSDL Structure
<definitions xmlns=" <types><!-- definition of types used in WSDL --></types> <message><!-- abstract definition of the data being transmitted --></message> <portType> <!-- a set of abstract operations refrring to input and output messages --> </portType> <binding><!-- concrete protocol and data format specs --></binding> <service><!-- specifies locations and bindings for a service --></service> </definitions>
121
SOAP: Basic Message Structure
<?xml version="1.0"?> <soap:Envelope xmlns:soap=" <soap:Header> <!-- Information to extend message --> <!-- For example WS-Security or transaction information --> </soap:Header> <soap:Body> <!-- Either the message contents or soap:Fault --> <soap:Fault> <!-- SOAP Fault structure and data --> </soap:Fault> </soap:Body> </soap:Envelope>
122
SOAP: The SoapClient Some SoapClient options:
SoapClient::__construct ( mixed wsdl [, array options] ) Some SoapClient options: location* (string) Location of Soap service uri* (string) Target namespace for the SOAP server style1 (int) Binding style for message (SOAP_DOCUMENT or SOAP_RPC) use1 (int) Binding type for style (SOAP_ENCODED or SOAP_LITERAL) trace (bool) Enable / disable request/response tracing (default disabled) exceptions (bool) Turn Soap exceptions on / off (default on) *Required in NON-WSDL mode 1 Only used in NON-WSDL mode
123
SOAP: The SoapClient Connection and security options for SoapClient:
SoapClient::__construct ( mixed wsdl [, array options] ) Connection and security options for SoapClient: login Login for HTTP authentication password Password for HTTP authenication proxy_host Host for Proxy server proxy_port Port for Proxy server proxy_login Login for Proxy server proxy_password Password for Proxy server local_cert Client certificate for HTTPS client authentication passphrase Passphrase for client certificate
124
SOAP: Function Query a WSDL soap/google/google_get_functions.php
try{ /* Create the SoapClient and load the WSDL */ $GoogleClient = new SoapClient('GoogleSearch.wsdl'); /* Retrieve all defined functions into an array */ $google_funcs = $GoogleClient->__getFunctions(); foreach($google_funcs AS $function) { echo $function."\n\n"; } } catch (SoapFault $e) { var_dump($e); ?>
125
SOAP: Function Query a WSDL Google Function RESULTS
base64Binary doGetCachedPage(string $key, string $url) string doSpellingSuggestion(string $key, string $phrase) GoogleSearchResult doGoogleSearch(string $key, string $q, int $start, int $maxResults, boolean $filter, string $restrict, boolean $safeSearch, string $lr, string $ie, string $oe) $key refers to a Google license key, which may be obatined from:
126
SOAP: Type Query a WSDL soap/google/google_get_types.php
try{ /* Create the SoapClient and load the WSDL */ $GoogleClient = new SoapClient('GoogleSearch.wsdl'); /* Retrieve all defined types into an array */ $types = $GoogleClient->__getTypes(); foreach($ types AS $type) { echo $type."\n\n"; } } catch (SoapFault $e) { var_dump($e); ?>
127
SOAP: Type Query a WSDL Google Type RESULTS
struct GoogleSearchResult { boolean documentFiltering; string searchComments; int estimatedTotalResultsCount; boolean estimateIsExact; ResultElementArray resultElements; string searchQuery; int startIndex; int endIndex; string searchTips; DirectoryCategoryArray directoryCategories; double searchTime; } ResultElement ResultElementArray[ ] DirectoryCategory DirectoryCategoryArray[ ] struct ResultElement { string summary; string URL; string snippet; string title; string cachedSize; boolean relatedInformationPresent; string hostName; DirectoryCategory directoryCategory; string directoryTitle; } struct DirectoryCategory { string fullViewableName; string specialEncoding;
128
SOAP: Retrieving from Google Cache soap/google/google_cache_client.php
/* The following file holds your registered Google key */ require('google_key.php'); try { /* Create the Soap Client */ $client = new SoapClient(' $cached = $client->doGetCachedPage($key, ' /* display first 200 characters of cached page */ echo substr($cached, 0, 500); } catch (SoapFault $e) { var_dump($e); } ?>
129
SOAP: Retrieving from Google Cache RESULTS
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <BASE HREF=" border=1 width=100%><tr><td><table border=1 bgcolor=#ffffff cellpadding=10 cellspacing=0 width=100% color=#ffffff><tr><td><font face="" color=black size=-1>This is <b><font color=#0039b6>G</font> <font color=#c41200>o</font> <font color=#f3c518>o</font> <font color=#0039b6>g</font> <font color=#30a72f>l</font> <font color=#c41200>e</font></b>'s <a href="
130
SOAP: Google Search Client soap/google/google_search_client.php
/* The following file holds your registered Google key */ require('google_key.php'); /* Define search criteria */ $search_terms = "PHP XML Web Services book"; $start = 0; $maxResults = 10; $filter = FALSE; $safeSearch = TRUE; $restrict = $lr = $ie = $oe = ""; /* Within Try/Catch block – omitted to save space */ /* Create the Soap Client */ $client = new SoapClient(' $results = $client->doGoogleSearch($key, $search_terms, $start, $maxResults, $filter, $restrict, $safeSearch, $lr, $ie, $oe)); var_dump($results); ?>
131
SOAP: Google Search Client RESULTS
object(stdClass)#2 (11) { ["documentFiltering"] => bool(false) ["searchComments"] => string(0) "" ["estimatedTotalResultsCount"]=> int( ) ["estimateIsExact"] => bool(false) ["resultElements"] => array(10) { [1] => object(stdClass)#5 (9) { ["summary"] => string(0) "" ["URL"]=> string(60) " ["snippet"] => string(116) "Amazon.com: Pro <b>PHP XML</b> and <b>Web Services</b> (Pro): <b>Books</b>: Robert Richards by Robert<br> Richards." ["title"] => string(91) "Amazon.com: Pro <b>PHP XML</b> and <b>Web Services</b> (Pro): <b>Books</b>: Robert Richards" ["cachedSize"] => string(3) "111k" ["relatedInformationPresent"] => bool(true) ["hostName"] => string(0) "" ["directoryCategory"] => object(stdClass)#6 (2) { ["fullViewableName"] => string(0) "" ["specialEncoding"] => string(0) "" } ["directoryTitle"] => string(0) ""
132
SOAP: Client Headers soap/headers.php
soapHeader::__construct ( string namespace, string name [, mixed data [, bool mustUnderstand [, mixed actor]]] ) <?php /* Create and authentication object with username/password */ class authentication { public $username; public $password; } $auth = new authentication(); $auth->username = 'MyUsername'; $auth->password = 'MyPassword'; /* You MUST encode the object */ $authVar = new SoapVar($auth, SOAP_ENC_OBJECT); $header = new SoapHeader('urn:ExampleAPI', "Authentication", $authVar, TRUE, SOAP_ACTOR_NEXT); /* Set the new headers to use when creating SOAP messages */ $sClient->__setSoapHeaders(array($header)); ?>
133
SOAP: Client Headers <SOAP-ENV:Envelope xmlns:ns2="urn:ExampleAPI" ..."> <SOAP-ENV:Header> <ns2:Authentication SOAP-ENV:mustUnderstand="1" SOAP-ENV:actor=" <ussername>MyUsername</username> <password>MyPassword</password> </ns2:Authentication> </SOAP-ENV:Header> .....
134
SOAP: Client Request Modification soap/google/request_modification.php
require('google_key.php'); Class mySoapClient extends SoapClient { function __doRequest($request, $location, $action, $version) { /* Load the request into a DOMDocument */ $dom = new DOMDocument(); $dom->loadXML($request); /* Find the url element and set url to */ $nodeList = $dom->getElementsByTagName('url'); if ($nodeList->length == 1) { $nodeList->item(0)->firstChild->nodeValue = " } /* Serialize the tree and send modified request to parent method */ $request = $dom->saveXML(); return parent::__doRequest($request, $location, $action, $version); $sClient = new mySoapClient('GoogleSearch.wsdl'); $cached = $sClient->doGetCachedPage($key, ' echo substr($cached, 1500, 700)."\n";
135
SOAP: Client Request Modification RESULTS (soap/google/request_modification.php)
ont><br><br><center><font size=-2><i>Google is neither affiliated with the authors of this page nor responsible for its content.</i></font></center></td></tr></table></td></tr></table> <hr> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>PHP: Hypertext Preprocessor</title> <link rel="stylesheet" href=" /> <link rel="stylesheet" href=" /> <link rel="shortcut icon" href=" /> <link rel="alternate" type="application/rss+xml" title="PHP: Hypertext Preprocessor" href=" /> <script language
136
SOAP: Debugging Client Requests soap/google/debug_client.php
/* Empty key so function will throw SoapFault */ $key = ""; $client_options = array ('trace'=>1); try { /* Create the Soap Client with debug option */ $client = new SoapClient(' $client_options); $cached = $client->doGetCachedPage($key, ' } catch (SoapFault $e) { print "Last Request Headers: \n".$client->__getLastRequestHeaders()."\n\n"; print "Last Request: \n".$client->__getLastRequest()."\n\n"; print "Last Response Headers: \n".$client->__getLastResponseHeaders()."\n\n"; print "Last Response: \n".$client->__getLastResponse()."\n"; }
137
SOAP: Debugging Client Request RESULT
Last Request Headers: POST /search/beta2 HTTP/1.1 Host: api.google.com Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "urn:GoogleSearchAction" Content-Length: 554 Last Request: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV=" xmlns:ns1="urn:GoogleSearch" xmlns:xsd=" xmlns:xsi=" xmlns:SOAP-ENC=" SOAP-ENV:encodingStyle=" xsi:type="xsd:string"></key><url xsi:type="xsd:string">
138
SOAP: Debugging Client Requests RESULT Continued
Last Response Headers: POST /search/beta2 HTTP/1.1 Host: api.google.com Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "urn:GoogleSearchAction" Content-Length: 554 Last Response: <?xml version='1.0' encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP-ENV=" xmlns:xsi=" xmlns:xsd=" <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server</faultcode> <faultstring>Exception from service object: Invalid authorization key: </faultstring> <faultactor>/search/beta2</faultactor> <detail> <stackTrace>com.google.soap.search.GoogleSearchFault: Invalid authorization key: at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(QueryLimits.java:213) . . .</stackTrace> </detail> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
139
SOAP: Client and Document/Literal soap/docliteral/amazonec_funcs.php
$wsdl = " try { /* Create the Soap Client to an Amazon ECS Search */ $client = new SoapClient($wsdl); print "Functions: \n"; $functions = $client->__getFunctions(); foreach($functions AS $function) { echo $function."\n"; } print "\nTypes: \n"; $types = $client->__getTypes(); foreach($types AS $type) { echo $type."\n\n"; } catch (SoapFault $e) { var_dump($e); ?>
140
SOAP: Client and Document/Literal RESULTS (soap/docliteral/amazonec_ funcs.php)
Functions: HelpResponse Help(Help $body) ItemSearchResponse ItemSearch(ItemSearch $body) ItemLookupResponse ItemLookup(ItemLookup $body) BrowseNodeLookupResponse BrowseNodeLookup(BrowseNodeLookup $body) … Types: struct ItemLookup { string MarketplaceDomain; string AWSAccessKeyId; ItemLookupRequest Shared; ItemLookupRequest Request; } struct ItemLookupResponse { OperationRequest OperationRequest; Items Items; struct ItemLookupRequest { string MerchantId; positiveInteger OfferPage; string ItemId; string SearchInsideKeywords; } struct Items { Request Request; nonNegativeInteger TotalResults; nonNegativeInteger TotalPages; Item Item;
141
SOAP: Client and Document/Literal soap/docliteral/ amazonec.php
class ItemLookup { public $MarketplaceDomain; public $AWSAccessKeyId; public $Request; } class ItemLookupRequest { public $ItemId; } $AWSAccessKeyId = '<Your AWS Access Key >; $wsdl = " $client = new SoapClient($wsdl); $params = new ItemLookup(); $params->AWSAccessKeyId = $AWSAccessKeyId $params->Request = new ItemLookupRequest(); $params->Request->ItemId = ' '; $results = $client->ItemLookup($params); var_dump($results);
142
SOAP: Client and Document/Literal RESULTS (soap/docliteral/ amazonec
SOAP: Client and Document/Literal RESULTS (soap/docliteral/ amazonec.php) . . . ["Item"]=> object(stdClass)#13 (3) { ["ASIN"]=>string(10) " " ["DetailPageURL"]=>string(173) " ["ItemAttributes"]=> object(stdClass)#14 (4) { ["Author"]=>string(15) "Robert Richards" ["Manufacturer"]=>string(6) "Apress" ["ProductGroup"]=>string(4) "Book" ["Title"]=>string(34) "Pro PHP XML and Web Services (Pro)" }
143
SOAP: Server WSDL (using Document/Literal) soap/server/exampleapi.wsdl
<xsd:element name="getPeopleByFirstLastName"> <xsd:complexType> <xsd:sequence> <xsd:element name="first" type="xsd:string"/> <xsd:element name="last" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="Person"> <xsd:all> <xsd:element name="id" type="xsd:int"/> <xsd:element name="lastName" type="xsd:string"/> <xsd:element name="firstName" type="xsd:string"/> </xsd:all> <xsd:element name="getPeopleByFirstLastNameResponse" type="tns:ArrayOfPerson"/> <message name="getPeopleByFirstLastName"> <part name="parameters" element="tns:getPeopleByFirstLastName"/> </message> <message name="getPeopleByFirstLastNameResponse"> <part name="result" element="tns:getPeopleByFirstLastNameResponse"/>
144
SOAP: Server soap/server/soap_server.php
/* System status - TRUE indicates normal operation / FALSE indicates down for maintenance */ $SYS_STATUS = TRUE; function findPeople($firstName, $lastName) { /* Initialize the Person Records */ $matching = array(); $people = array(array('id'=>1, 'firstName'=>'John', 'lastName'=>'Smith'), array('id'=>2, 'firstName'=>'Jane', 'lastName'=>'Doe')); foreach($people AS $person) { /* Check if match on first name */ if (empty($firstSearch) || preg_match('/^'.$firstSearch.'$/i', $person['firstName'])) { /* Check if match on last name */ if (empty($lastSearch) || preg_match('/^'.$lastSearch.'$/i', $person['lastName'])) { $matching[ ] = $person; } return $matching;
145
SOAP: Server soap/server/soap_server.php
function getPeopleByFirstLastName($getPeopleByFirstLastName) { /* If system is down throw SOAP fault */ if (isset($GLOBALS['SYS_STATUS']) && $GLOBALS['SYS_STATUS'] == FALSE) { $details = array("SysMessage"=>"Sys Error", "RetryInMinutes"=>60); /* SoapFault::__construct ( string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, SoapHeader headerfault]]]] ) */ throw new SoapFault("SYSError", "System Unavailable", "urn:ExampleAPI", $details, "sysmaint"); } $firstSearch = str_replace('*', '([a-z]*)', $getPeopleByFirstLastName->first); $lastSearch = str_replace('*', '([a-z]*)', $getPeopleByFirstLastName->last); $retval = array(); $results = findPeople($firstSearch, $lastSearch); foreach($results AS $result) { /* Add matching records as an encoded SoapVar */ $retval[] = new SoapVar($result, SOAP_ENC_ARRAY, "Person", "urn:ExampleAPI"); return $retval;
146
SOAP: Server soap/server/soap_server.php
/* Create the server using WSDL and specify the actor URI */ $sServer = new SoapServer("exampleapi.wsdl", array('actor'=>'urn:ExampleAPI')); /* Register the getPeopleByFirstLastName function */ $sServer->addFunction("getPeopleByFirstLastName"); /* Handle the SOAP request */ $sServer->handle(); ?>
147
SOAP: Calling our Server soap/server/soap_client.php
try { $sClient = new SoapClient('exampleapi.wsdl'); /* Set search parameters */ $params = array('first'=>'jo*', 'last'=>'*'); /* Make request and dump response */ $response = $sClient->getPeopleByFirstLastName($params); var_dump($response); } catch (SoapFault $e) { /* Dump any caught SoapFault exceptions */ var_dump($e); } ?>
148
SOAP: Calling our Server RESULTS
array(1) { [0]=> object(stdClass)#2 (3) { ["id"]=> int(1) ["lastName"]=> string(5) "Smith" ["firstName"]=> string(4) "John" }
149
SOAP: Modifying A Request
$dom = DOMDocument::loadXML(file_get_contents('php://input')); $soapNS = $dom->documentElement->namespaceURI; $soapXPath = new DOMXPath($doc); $soapXPath ->registerNamespace('wssoap', $soapNS); $soapXPath ->registerNamespace('wssephp', ' $headers = $soapXPath->query('//wssoap:Envelope/wssoap:Header/wssephp:Security'); if ($security = $headers->item(0)) { $actor = $security->getAttributeNS($soapNS, 'actor'); /* Code here first checks to make sure actor is correct for this header */ if (/* actor is empty or actor specifies this server */) { /* Handle WS-Security and then remove Security element */ $security->parentElement->removeChild($security); } /* If Header is empty it also can be removed */ /* Process request */ $soapServer->handle($dom->saveXML()); Loading the document as a string here just in case it needs to be changed to $GLOBALS['HTTP_RAW_POST_DATA'] to support the developers environment.
150
Questions?
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.