Advanced XML with PHP 5 - CDATA Zone

Post on 12-Sep-2021

8 views 0 download

transcript

Advanced XML Advanced XML with PHP 5with PHP 5

March 14, 2007March 14, 2007Robert RichardsRobert Richards

rrichards@ctindustries.netrrichards@ctindustries.nethttp://www.cdatazone.org/talks/quebec_2007/workshop.ziphttp://www.cdatazone.org/talks/quebec_2007/workshop.zip

AgendaAgenda� Introduction to Terms and ConceptsIntroduction to Terms and Concepts� LibxmlLibxml� SimpleXMLSimpleXML� SDOSDO� DOMDOM� XMLReaderXMLReader� XMLWriterXMLWriter� XSLXSL

XML NamespacesXML Namespaces

� An XML Namespace is a collection of names An XML Namespace is a collection of names identified by a URI.identified by a URI.

� They are applicable to elements and attributes.They are applicable to elements and attributes.� Namespaces may or may not be associated with a Namespaces may or may not be associated with a

prefix.prefix.� xmlns:rob="urn:rob"xmlns:rob="urn:rob"� xmlns=xmlns=http://www.example.com/robhttp://www.example.com/rob

� Attributes never reside within a default namespace.Attributes never reside within a default namespace.� It is illegal to have two attributes with the same It is illegal to have two attributes with the same

localname and same namespace on the same element.localname and same namespace on the same element.

XML Namespace ExampleXML 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>

XML Namespace ExampleXML 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>

Illegal Namespace UsageIllegal Namespace Usage<order num="1001" xmlns="urn:order"<order num="1001" xmlns="urn:order"

xmlns:order="urn:order"xmlns:order="urn:order" xmlns:ship="urn:order"xmlns:ship="urn:order" >>

<shipping ship:type="fed_ex" type="fed_ex"><shipping ship:type="fed_ex" type="fed_ex">

<name <name ship:type="care_of"ship:type="care_of"

order:type="legal"order:type="legal" >John Smith</ship:name>>John Smith</ship:name>

</ship:shipping></ship:shipping>

</order></order>

Both "type" attributes are bound to same namespace which is not valid!

Illegal Namespace UsageIllegal Namespace Usage<order num="1001" xmlns="urn:order"<order num="1001" xmlns="urn:order"

xmlns:order="urn:order"xmlns:order="urn:order"

xmlns:ship="urn:order">xmlns:ship="urn:order">

<shipping <shipping ship:type="fed_ex" type="fed_ex"ship:type="fed_ex" type="fed_ex" >>

<name ship:type="care_of" <name ship:type="care_of"

order:type="legal">John Smith</ship:name>order:type="legal">John Smith</ship:name>

</ship:shipping></ship:shipping>

</order></order>

<!-- attributes on shipping element are valid ! --><!-- attributes on shipping element are valid ! -->

Reserved Namespaces and Reserved Namespaces and PrefixesPrefixes

� The prefix The prefix xmlxml is bound to is bound to http://www.w3.org/XML/1998/namespacehttp://www.w3.org/XML/1998/namespace..

� The prefix The prefix xmlnsxmlns is bound to is bound to http://www.w3.org/2000/xmlns/http://www.w3.org/2000/xmlns/..

� Prefixes should also not begin with the Prefixes should also not begin with the characters characters xmlxml..

Schemas and ValidationSchemas and Validation

� Validation insures an XML document Validation insures an XML document conforms to a set of defined rules.conforms to a set of defined rules.

� Multiple mechanisms exist to write document Multiple mechanisms exist to write document rule sets:rule sets:� Document Type Definition (DTD)Document Type Definition (DTD)� XML SchemaXML Schema� RelaxNGRelaxNG

Document Type Definition Document Type Definition (DTD)(DTD)validation/courses-dtd.xmlvalidation/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>2004-09-01T11:13:01</lastmodified> </course></courses>

DTD and IDsDTD and IDsvalidation/course-id.xmlvalidation/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></courses>

XML SchemaXML Schemavalidation/course.xsdvalidation/course.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="courses"> <xsd:complexType> <xsd:sequence> <xsd:element name="course" minOccurs="1" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <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:sequence> </xsd:complexType> </xsd:element></xsd:schema>

RelaxNGRelaxNGvalidation/course.rngvalidation/course.rng

<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

<start> <element name="courses"> <oneOrMore> <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> </oneOrMore> </element> </start>

</grammar>

XPathXPath

� Language to locate and retrieve information Language to locate and retrieve information from an XML documentfrom an XML document

� A foundation for XSLTA foundation for XSLT� An XML document is a tree containing nodesAn XML document is a tree containing nodes� The XML document is the root nodeThe XML document is the root node� Locations are addressable similar to the syntax Locations are addressable similar to the syntax

for a filesystemfor a filesystem

XPath Reference DocumentXPath Reference Documentxpath/courses.xmlxpath/courses.xml

<courses xmlns:t="http://www.example.com/title">

<course xml:id="c2"> <t:title>French I</t:title> <description>Introduction to French</description> </course>

<course xml:id="c3"> <t:title>French II</t:title> <description>Intermediate French</description> <pre-requisite cref="c2" /> <defns xmlns="urn::default">content</defns> </course>

</courses>

XPath Location ExampleXPath Location Examplexpath/location.phpxpath/location.php

/courses/course/description/courses/*/description//description//description[ancestor::course]

Expression:

Resulting Nodset:

<description>Introduction to French</description><description>Intermediate French</description>

XPath Function ExampleXPath Function Examplexpath/function.phpxpath/function.php

string(/courses/course/pre-requisite[@cref="c2"]/..)string(/courses/course/pre-requisite[@cref="c2"]/..)

French IIFrench II Intermediate FrenchIntermediate French contentcontent

Reference:Reference:<courses xmlns:t="http://www.example.com/title"><courses xmlns:t="http://www.example.com/title"> <course xml:id="c3"><course xml:id="c3"> <!-- additional elements containing the textual content ommitted for brevity --><!-- additional elements containing the textual content ommitted for brevity --> <pre-requisite cref="c2" /><pre-requisite cref="c2" /> </course></course></courses></courses>

XPath and NamespacesXPath and Namespacesxpath/namespaces.phpxpath/namespaces.php

//titleEmpty NodeSet

//defnsEmpty NodeSet

<defns xmlns="urn:default">content</defns>

//t:title<t:title>French I</t:title><t:title>French II</t:title>

//*[local-name()="defns"]

<courses xmlns:t="http://www.example.com/title"> <course xml:id="c2"> <t:title>French I</t:title> </course>

<course xml:id="c3"> <t:title>French II</t:title> <defns xmlns="urn::default">content</defns> </course></courses>

Reference:

PHP and XMLPHP and XML

� PHP 5 introduced numerous interfaces for PHP 5 introduced numerous interfaces for working with XMLworking with XML

� The libxml2 library (http://www.xmlsoft.org/) The libxml2 library (http://www.xmlsoft.org/) was chosen to provide XML supportwas chosen to provide XML support

� The sister library libxslt provides XSLT supportThe sister library libxslt provides XSLT support� I/O is handled via PHP streamsI/O is handled via PHP streams� ext/domxml was removed in favor of ext/domext/domxml was removed in favor of ext/dom

XML Entensions for PHP 5XML Entensions for PHP 5

� ext/libxmlext/libxml� ext/xml (SAX push parser)ext/xml (SAX push parser)� ext/domext/dom� ext/simplexmlext/simplexml� ext/xmlreader (pull parser)ext/xmlreader (pull parser)� pecl/sdo (SCA_SDO)pecl/sdo (SCA_SDO)� ext/xmlwriterext/xmlwriter� ext/xslext/xsl� ext/wddxext/wddx� ext/soapext/soap

LibxmlLibxml

� Contains common functionality shared across Contains common functionality shared across extensions.extensions.

� Defines constants to modify parse time Defines constants to modify parse time behavior.behavior.

� Provides access to streams context.Provides access to streams context.� Allows modification of error handling Allows modification of error handling

behavior for XML based extensions.behavior for XML based extensions.

Libxml: Parser OptionsLibxml: Parser Options

Disable network access when loadingLIBXML_NONET

Merge CDATA nodes in Text nodesLIBXML_NOCDATA

Perform XIncludes during parsingLIBXML_XINCLUDE

Remove insignificant whitespace on parsingLIBXML_NOBLANKS

Suppress parser warnings from libxml2LIBXML_NOWARNING

Suppress parsing errors from libxml2LIBXML_NOERROR

Loads subsets and perform validationLIBXML_DTDVALID

Create defaulted attributes defined in DTDLIBXML_DTDATTR

Load subsets but do not perform validationLIBXML_DTDLOAD

Substitute entities with replacement contentLIBXML_NOENT

Libxml: Error HandlingLibxml: Error Handling

bool libxml_use_internal_errors ([bool use_errors])bool libxml_use_internal_errors ([bool use_errors])

void libxml_clear_errors ( void )void libxml_clear_errors ( void )

LibXMLError libxml_get_last_error ( void )LibXMLError libxml_get_last_error ( void )

array libxml_get_errors ( void )array libxml_get_errors ( void )

Libxml: LibXMLErrorLibxml: LibXMLError

Class: LibXMLErrorProperties (Read-Only):

(int) level(int) code(int) column(string) message(string) file(int) line

LibXMLError::code Values:LIBXML_ERR_NONELIBXML_ERR_WARNINGLIBXML_ERR_ERRORLIBXML_ERR_FATAL

LibXMLError ExampleLibXMLError Examplelibxml/error.phplibxml/error.php

<?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";}?>

LibXMLError ResultLibXMLError Result

PHP Warning: DOMDocument::loadXML(): Premature end of data in tag root line 1 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 4in 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 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 4Entity, line: 1 in /home/rrichards/workshop/libxml/error.php on line 4

New Error Handling:New Error Handling:object(LibXMLError)#2 (6) {object(LibXMLError)#2 (6) { ["level"]=> int(3)["level"]=> int(3) ["code"]=> int(4)["code"]=> int(4) ["column"]=> int(1)["column"]=> int(1) ["message"]=> string(34) "Start tag expected, '<' not found"["message"]=> string(34) "Start tag expected, '<' not found" ["file"]=> string(0) ""["file"]=> string(0) "" ["line"]=> int(1)["line"]=> int(1)}}

Libxml: Stream ContextLibxml: Stream Context

$opts = array($opts = array(

'http' => array('http' => array('user_agent' => 'PHP libxml2 agent','user_agent' => 'PHP libxml2 agent',

'proxy' => 'tcp://localhost:8082','proxy' => 'tcp://localhost:8082',

'request_fulluri' => TRUE'request_fulluri' => TRUE

))););

$context = stream_context_create($opts);$context = stream_context_create($opts);libxml_set_streams_context($context);libxml_set_streams_context($context);

$doc = DOMDocument::load('http://www.example.org/file.xml');$doc = DOMDocument::load('http://www.example.org/file.xml');

Preparing for Unicode in PHP 6Preparing for Unicode in PHP 6

� XML extensions are unicode ready for PHP 6XML extensions are unicode ready for PHP 6� Both the UTF-8 binary strings (existing behavior) Both the UTF-8 binary strings (existing behavior)

ANDAND unicode strings. unicode strings.� With Unicode enabled, unicode strings are returned With Unicode enabled, unicode strings are returned

instead of the current UTF-8 binary strings.instead of the current UTF-8 binary strings.

� Binary strings are required for Loading and Binary strings are required for Loading and Saving Saving StringString based XML documents based XML documents� Insures original encoding is not lostInsures original encoding is not lost� Does not affect usage with unicode disabledDoes not affect usage with unicode disabled

Forward CompatibilityForward Compatibility

$xml = $xml = (binary)(binary) "<root>My Document</root>";"<root>My Document</root>";$sxe = simplexml_load_string($xml);$sxe = simplexml_load_string($xml);

$xml = $xml = bb'<root>MyDocument</root>';'<root>MyDocument</root>';$dom = new DOMDocument();$dom = new DOMDocument();$dom->loadXML($xml);$dom->loadXML($xml);

$sxe = simplexml_load_string($dom->saveXML());$sxe = simplexml_load_string($dom->saveXML());

SimpleXMLSimpleXML

� Provides simple access to XML documentsProvides simple access to XML documents� Operates only on elements and attributesOperates only on elements and attributes� Contains XPath supportContains XPath support� Allows for modifications to the XMLAllows for modifications to the XML� Zero copy interoperability with DOMZero copy interoperability with DOM� Examples for PHP 5.1.6+Examples for PHP 5.1.6+� New in PHP 5.1.3New in PHP 5.1.3

� Elements and attributes can be added using addChild() and Elements and attributes can be added using addChild() and addAttribute() methods.addAttribute() methods.

� Node names can be retrieved by calling getName().Node names can be retrieved by calling getName().

SimpleXML: Consuming Yahoo WebSearch SimpleXML: Consuming Yahoo WebSearch simplexml/yahoo_websearch_results.xmlsimplexml/yahoo_websearch_results.xml

<ResultSet <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" totalResultsReturnedtotalResultsReturned="3" firstResultPosition="1">="3" firstResultPosition="1">

<<ResultResult>> <<TitleTitle>Zend Technologies - PHP 5 . . .</Title>>Zend Technologies - PHP 5 . . .</Title> <Summary>titletext = $dom-&amp;gt;createText. . .</Summary><Summary>titletext = $dom-&amp;gt;createText. . .</Summary> <<UrlUrl >http://www.zend.com/php5/articles/php5-x. . .</Url>>http://www.zend.com/php5/articles/php5-x. . .</Url> <ClickUrl>http://uk.wrs.yahoo.com/_ylt=...</ClickUrl><ClickUrl>http://uk.wrs.yahoo.com/_ylt=...</ClickUrl> <DisplayUrl>www.zend.com/php5/articles/php. . .</DisplayUrl><DisplayUrl>www.zend.com/php5/articles/php. . .</DisplayUrl> <<ModificationDateModificationDate>1171872000</ModificationDate>>1171872000</ModificationDate> <MimeType>text/html</MimeType><MimeType>text/html</MimeType> <!-- Abbreviated Content --><!-- Abbreviated Content --> </Result></Result>

<!-- Abbreviated Response --><!-- Abbreviated Response --></ResultSet></ResultSet>

SimpleXML: Consuming Yahoo WebSearch SimpleXML: Consuming Yahoo WebSearch simplexml/yahoo_search.phpsimplexml/yahoo_search.php

/* URL to Web Search service *//* URL to Web Search service */$url = 'http://api.search.yahoo.com/WebSearchService/V1/webSearch';$url = 'http://api.search.yahoo.com/WebSearchService/V1/webSearch';/* The query is separate here as the terms must be encoded. *//* The query is separate here as the terms must be encoded. */$url .= '?query='.rawurlencode('php5 xml');$url .= '?query='.rawurlencode('php5 xml');/* Complete the URL adding App ID, limit to 3 results and only English results *//* Complete the URL adding App ID, limit to 3 results and only English results */$url .= "&appid=zzz&results=3&language=en";$url .= "&appid=zzz&results=3&language=en";

$sxe = simplexml_load_file($url);$sxe = simplexml_load_file($url);

/* Check for number of results returned *//* Check for number of results returned */if ((int)$sxe['totalResultsReturned'] > 0) {if ((int)$sxe['totalResultsReturned'] > 0) {

/* Loop through results and print title, url and modification date *//* Loop through results and print title, url and modification date */ foreach ($sxe->Result AS $result) {foreach ($sxe->Result AS $result) { print 'Title: '.$result->Title."\n";print 'Title: '.$result->Title."\n"; print 'Url: '.$result->Url."\n";print 'Url: '.$result->Url."\n"; print 'Mod Date: '.date ('M d Y', (int)$result->ModificationDate)."\n\n";print 'Mod Date: '.date ('M d Y', (int)$result->ModificationDate)."\n\n"; }}}}

SimpleXML: Consuming Yahoo WebSearch SimpleXML: Consuming Yahoo WebSearch RESULTSRESULTS

Title: Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New?Title: Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New?Url: http://www.zend.com/php5/articles/php5-xmlphp.phpUrl: http://www.zend.com/php5/articles/php5-xmlphp.phpMod Date: Feb 19 2007Mod Date: Feb 19 2007

Title: Zend Developer Zone | XML in PHP 5 - What's New?Title: Zend Developer Zone | XML in PHP 5 - What's New?Url: http://devzone.zend.com/node/view/id/1713Url: http://devzone.zend.com/node/view/id/1713Mod Date: Feb 26 2007Mod Date: Feb 26 2007

Title: FreshPorts -- textproc/php5-xmlTitle: FreshPorts -- textproc/php5-xmlUrl: http://www.freshports.org/textproc/php5-xmlUrl: http://www.freshports.org/textproc/php5-xmlMod Date: Feb 15 2007Mod Date: Feb 15 2007

SimpleXML: NamespacesSimpleXML: Namespacessimplexml/sxe_ns_books.phpsimplexml/sxe_ns_books.php

<books <books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book">> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name><bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price><bk:price>12.99</bk:price> </bk:book></bk:book>

<book qty="33" xmlns="http://www.example.com/ExteralClassics"><book qty="33" xmlns="http://www.example.com/ExteralClassics"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <price>10.99</price><price>10.99</price> </book></book></books></books>

$books = simplexml_load_file('sxe_ns_books.xml');$books = simplexml_load_file('sxe_ns_books.xml');

foreach ($books->book AS $book) {foreach ($books->book AS $book) { if ($book->if ($book->namename)) print $book->name;print $book->name;}}

SimpleXML: Namespaces SimpleXML: Namespaces ResultsResults

To Kill a MockingbirdTo Kill a Mockingbird

Question:Question:

What happened to the other book title?What happened to the other book title?

SimpleXML: NamespacesSimpleXML: Namespacessimplexml/sxe_ns_books_prefix.phpsimplexml/sxe_ns_books_prefix.php

<books <books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book">> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name><bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price><bk:price>12.99</bk:price> </bk:book></bk:book>

<book qty="33" xmlns="http://www.example.com/ExteralClassics"><book qty="33" xmlns="http://www.example.com/ExteralClassics"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <price>10.99</price><price>10.99</price> </book></book></books></books>

$books = simplexml_load_file('sxe_ns_books.xml');$books = simplexml_load_file('sxe_ns_books.xml');

$children = $books->children("http://www.example.com/book");$children = $books->children("http://www.example.com/book");foreach ($children->book AS $book) {foreach ($children->book AS $book) { print $book->name."\n";print $book->name."\n";}}

SimpleXML: Namespaces SimpleXML: Namespaces ResultsResults

Grapes of WrathGrapes of Wrath

Only book elements within the specified Only book elements within the specified namespace are used in the resultsnamespace are used in the results

SimpleXML: XpathSimpleXML: Xpathsimplexml/sxe_xpath_ns.phpsimplexml/sxe_xpath_ns.php

<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"><books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name><bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price><bk:price>12.99</bk:price> </bk:book></bk:book> <book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"><book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <pc:price>10.99</pc:price><pc:price>10.99</pc:price> </book></book></books></books>

$sxe = simplexml_load_file('$sxe = simplexml_load_file('sxe_ns_books.xmlsxe_ns_books.xml');');

$nodelist = $sxe->xpath("//name");$nodelist = $sxe->xpath("//name");print "Book Title: ".$nodelist[0]."\n";print "Book Title: ".$nodelist[0]."\n";

$nodelist = $sxe->xpath("//bk:name");$nodelist = $sxe->xpath("//bk:name");print "Book Title: ".$nodelist[0]."\n";print "Book Title: ".$nodelist[0]."\n";

SimpleXML: XPath ResultsSimpleXML: XPath Results

Book Title: Book Title:

Book Title: Book Title: Grapes of WrathGrapes of Wrath

Why doesn't the title "Why doesn't the title "To Kill a Mockingbird" To Kill a Mockingbird" get printed?get printed?

SimpleXML: XpathSimpleXML: Xpathsimplexml/sxe_xpath_ns_def.phpsimplexml/sxe_xpath_ns_def.php

<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"><books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name><bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price><bk:price>12.99</bk:price> </bk:book></bk:book> <book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"><book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <pc:price>10.99</pc:price><pc:price>10.99</pc:price> </book></book></books></books>

$sxe = simplexml_load_file('$sxe = simplexml_load_file('sxe_ns_books.xmlsxe_ns_books.xml');');

$sxe->registerXPathNamespace("ec", "$sxe->registerXPathNamespace("ec", "http://www.example.com/ExteralClassicshttp://www.example.com/ExteralClassics");");

$nodelist = $sxe->xpath("//ec:name");$nodelist = $sxe->xpath("//ec:name");print "Book Title: ".$nodelist[0]."\n";print "Book Title: ".$nodelist[0]."\n";

Book Title: To Kill a MockingbirdBook Title: To Kill a Mockingbird

SimpleXML: XPath ContextSimpleXML: XPath Contextsimplexml/sxe_xpath_context.phpsimplexml/sxe_xpath_context.php

$xml = <<< EOXML$xml = <<< EOXML<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"><books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"> <book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"><book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <pc:price>10.99</pc:price><pc:price>10.99</pc:price> </book></book></books></books>EOXML;EOXML;

libxml_use_internal_errors(TRUE);libxml_use_internal_errors(TRUE);

$books = simplexml_load_string($xml);$books = simplexml_load_string($xml);$books->registerXPathNamespace("pc", "urn::pricing");$books->registerXPathNamespace("pc", "urn::pricing");

$nodelist = $books->xpath("//ec:name");$nodelist = $books->xpath("//ec:name");$pricing = $books->book->xpath("./pc:price");$pricing = $books->book->xpath("./pc:price");print "Book Price: $".$pricing[0]."\n";print "Book Price: $".$pricing[0]."\n";

RESULTSRESULTSBook Price: $Book Price: $

SimpleXML: XPath ContextSimpleXML: XPath Contextsimplexml/sxe_xpath_ns_context.phpsimplexml/sxe_xpath_ns_context.php

$xml = <<< EOXML$xml = <<< EOXML<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"><books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"> <book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"><book qty="33" xmlns="http://www.example.com/ExteralClassics" xmlns:pc="urn::pricing"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <pc:price>10.99</pc:price><pc:price>10.99</pc:price> </book></book></books></books>EOXML;EOXML;

$books = simplexml_load_string($xml);$books = simplexml_load_string($xml);

$book = $books->book[0]; $book = $books->book[0]; /* GOTCHA TO BE AWARE OF*//* GOTCHA TO BE AWARE OF*/$book->registerXPathNamespace("pc", "urn::pricing");$book->registerXPathNamespace("pc", "urn::pricing");

$pricing = $book->xpath("./pc:price");$pricing = $book->xpath("./pc:price");

print "Book Price: $".$pricing[0]."\n";print "Book Price: $".$pricing[0]."\n";

RESULTSRESULTSBook Price: $10.99Book Price: $10.99

SimpleXML: Write some dataSimpleXML: Write some data

$data = "<root><top><![CDATA[ Some text]]></top></root>";$data = "<root><top><![CDATA[ Some text]]></top></root>";

/* We can even pass libxml parser options *//* We can even pass libxml parser options */$sxe = new SimpleXMLElement($data, LIBXML_NOCDATA);$sxe = new SimpleXMLElement($data, LIBXML_NOCDATA);

$sxe->child = 'new child';$sxe->child = 'new child';$sxe->child2 = 'second child';$sxe->child2 = 'second child';

print $sxe->asXML();print $sxe->asXML();

<?xml version="1.0"?><?xml version="1.0"?><root><top> Some text</top><child>new <root><top> Some text</top><child>new child</child><child2>second child</child2></root>child</child><child2>second child</child2></root>

SimpleXML: Reading Data can SimpleXML: Reading Data can Create Data?Create Data?

ISSUE IS RESOLVED IN PHP 5.2.1+ISSUE IS RESOLVED IN PHP 5.2.1+

$sxe = new SimpleXMLElement("<root />");$sxe = new SimpleXMLElement("<root />");

foreach ($sxe->childr AS $child) {foreach ($sxe->childr AS $child) { var_dump($child);var_dump($child);}}print $sxe->asXML();print $sxe->asXML();

????? RESULTS ?????????? RESULTS ?????<?xml version="1.0"?><?xml version="1.0"?><root><childr/></root><root><childr/></root>

SimpleXML: Advanced EditingSimpleXML: Advanced Editingsimplexml/editing.phpsimplexml/editing.php

$data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'), $data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'), array('title'=>'Result 2', 'descript'=>'description of Res2'), array('title'=>'Result 2', 'descript'=>'description of Res2'), array('title'=>'Result 3', 'descript'=>'This is result 3'));array('title'=>'Result 3', 'descript'=>'This is result 3'));

class webservice extends simpleXMLElement {class webservice extends simpleXMLElement { public function appendElement($name, $value=NULL) {public function appendElement($name, $value=NULL) { $count = (isset($this->{$name}))?count($this->{$name}):0;$count = (isset($this->{$name}))?count($this->{$name}):0; if ($count) {if ($count) { $this->{$name}[$count] = $value;$this->{$name}[$count] = $value; } else { } else { /* An issue requires first child be created without offset *//* An issue requires first child be created without offset */ $this->{$name} = $value;$this->{$name} = $value; }} return $this->{$name}[$count];return $this->{$name}[$count];} }} }

$rest = simplexml_load_string('<results num="0" />', $rest = simplexml_load_string('<results num="0" />', 'webservice''webservice'););$rest['num'] = count($data);$rest['num'] = count($data);

foreach ($data AS $result_item) {foreach ($data AS $result_item) { $result = $rest->appendElement('result');$result = $rest->appendElement('result'); $result->appendElement('title', $result_item['title']);$result->appendElement('title', $result_item['title']); $result->appendElement('description', $result_item['descript']);$result->appendElement('description', $result_item['descript']);}}

print $rest->asXML();print $rest->asXML();

SimpleXML: Advanced Editing SimpleXML: Advanced Editing ResultsResults

<?xml version="1.0"?><?xml version="1.0"?><results num="3"><results num="3"> <result><result> <title>Result 1</title><title>Result 1</title> <description>Res1 description</description><description>Res1 description</description> </result></result> <result><result> <title>Result 2</title><title>Result 2</title> <description>description of Res2</description><description>description of Res2</description> </result></result> <result><result> <title>Result 3</title><title>Result 3</title> <description>This is result 3</description><description>This is result 3</description> </result></result></results></results>

SimpleXML: Advanced Editing SimpleXML: Advanced Editing PHP 5.1.3PHP 5.1.3

simplexml/editing_php513.phpsimplexml/editing_php513.php

$data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'),$data = array(array('title'=>'Result 1', 'descript'=>'Res1 description'), array('title'=>'Result 2', 'descript'=>'description of Res2'),array('title'=>'Result 2', 'descript'=>'description of Res2'), array('title'=>'Result 3', 'descript'=>'This is result 3'));array('title'=>'Result 3', 'descript'=>'This is result 3'));

$rest = simplexml_load_string('<results num="0" />');$rest = simplexml_load_string('<results num="0" />');$rest['num'] = count($data);$rest['num'] = count($data);

foreach ($data AS $result_item) {foreach ($data AS $result_item) { $result = $rest->$result = $rest->addChildaddChild('result');('result'); $result->$result->addChildaddChild('title', $result_item['title']);('title', $result_item['title']); $result->$result->addChildaddChild('description');('description'); $result->description = $result_item['descript'];$result->description = $result_item['descript'];}}

print $rest->asXML();print $rest->asXML();

SimpleXML: Removing data SimpleXML: Removing data remove_data.phpremove_data.php

<?php<?php$results = simplexml_load_file('editing_php513.xml');$results = simplexml_load_file('editing_php513.xml');

/* Delete title from first result element *//* Delete title from first result element */unset($results->result->title);unset($results->result->title);

/* Delete the 2nd result element - WORKS in PHP 5.1.3+ *//* Delete the 2nd result element - WORKS in PHP 5.1.3+ */unset($results->result[1]);unset($results->result[1]);

print $results->asXML();print $results->asXML();?>?>

SimpleXML: Removing data SimpleXML: Removing data RESULTSRESULTS

<?xml version="1.0"?><?xml version="1.0"?>

<results num="3"><results num="3">

<result><result>

<description>Res1 description</description><description>Res1 description</description>

</result></result>

<result><result>

<title>Result 3</title><title>Result 3</title>

<description>This is result 3</description><description>This is result 3</description>

</result></result>

</results></results>

SDO (SDO_DAS_XML)SDO (SDO_DAS_XML)

� Provides simple access to XML documentsProvides simple access to XML documents� Works in a similar fashion to SimpleXMLWorks in a similar fashion to SimpleXML� Operates only on elements and attributesOperates only on elements and attributes� Contains XPath supportContains XPath support� Allows for modifications to the XMLAllows for modifications to the XML� Requires XML SchemaRequires XML Schema� Stricter than SimpleXMLStricter than SimpleXML� Maps XML to Data TypesMaps XML to Data Types

SDO: Consuming Yahoo ContextSearch SDO: Consuming Yahoo ContextSearch sdo/yahoo_search_results.xmlsdo/yahoo_search_results.xml

<ResultSet <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" totalResultsReturnedtotalResultsReturned="3" firstResultPosition="1">="3" firstResultPosition="1">

<<ResultResult>> <<TitleTitle>Zend Technologies - PHP 5 . . .</Title>>Zend Technologies - PHP 5 . . .</Title> <Summary>titletext = $dom-&amp;gt;createText. . .</Summary><Summary>titletext = $dom-&amp;gt;createText. . .</Summary> <<UrlUrl >http://www.zend.com/php5/articles/php5-x. . .</Url>>http://www.zend.com/php5/articles/php5-x. . .</Url> <ClickUrl>http://uk.wrs.yahoo.com/_ylt=...</ClickUrl><ClickUrl>http://uk.wrs.yahoo.com/_ylt=...</ClickUrl> <<ModificationDateModificationDate>1171872000</ModificationDate>>1171872000</ModificationDate> <MimeType>text/html</MimeType><MimeType>text/html</MimeType> <!-- Abbreviated Content --><!-- Abbreviated Content --> </Result></Result>

<!-- Abbreviated Response --><!-- Abbreviated Response --></ResultSet></ResultSet>

SDO: Consuming Yahoo ContextSearchSDO: Consuming Yahoo ContextSearchsdosdo/yahoo_search.php/yahoo_search.php

/* URL to Web Search service *//* URL to Web Search service */$url = 'http://search.yahooapis.com/WebSearchService/V1/contextSearch';$url = 'http://search.yahooapis.com/WebSearchService/V1/contextSearch';$url .= '?query='.rawurlencode('php5 xml')."&appid=zzz&results=3&language=en&context=internet";$url .= '?query='.rawurlencode('php5 xml')."&appid=zzz&results=3&language=en&context=internet";

$xsd = "http://search.yahooapis.com/WebSearchService/V1/WebSearchResponse.xsd";$xsd = "http://search.yahooapis.com/WebSearchService/V1/WebSearchResponse.xsd";$xmldas = SDO_DAS_XML::create($xsd);$xmldas = SDO_DAS_XML::create($xsd);

$document = $xmldas->loadFile($url);$document = $xmldas->loadFile($url);

$sxe = $document->getRootDataObject();$sxe = $document->getRootDataObject();

/* Check for number of results returned *//* Check for number of results returned */if ((int)$sxe['totalResultsReturned'] > 0) {if ((int)$sxe['totalResultsReturned'] > 0) {

/* Loop through results and print title, url and modification date *//* Loop through results and print title, url and modification date */ foreach ($sxe->Result AS $result) {foreach ($sxe->Result AS $result) { print 'Title: '.$result->Title."\n";print 'Title: '.$result->Title."\n"; print 'Url: '.$result->Url."\n";print 'Url: '.$result->Url."\n"; print 'Mod Date: '.date ('M d Y', (int)$result->ModificationDate)."\n\n";print 'Mod Date: '.date ('M d Y', (int)$result->ModificationDate)."\n\n"; }}}}

SDO: Consuming Yahoo ContextSearchSDO: Consuming Yahoo ContextSearchsdosdo/yahoo_search2.php/yahoo_search2.php

/* URL to Web Search service *//* URL to Web Search service */$url = 'http://search.yahooapis.com/WebSearchService/V1/contextSearch';$url = 'http://search.yahooapis.com/WebSearchService/V1/contextSearch';$url .= '?query='.rawurlencode('php5 xml')."&appid=zzz&results=3&language=en&context=internet";$url .= '?query='.rawurlencode('php5 xml')."&appid=zzz&results=3&language=en&context=internet";

$xsd = "http://search.yahooapis.com/WebSearchService/V1/WebSearchResponse.xsd";$xsd = "http://search.yahooapis.com/WebSearchService/V1/WebSearchResponse.xsd";$xmldas = SDO_DAS_XML::create($xsd);$xmldas = SDO_DAS_XML::create($xsd);

$document = $xmldas->loadFile($url);$document = $xmldas->loadFile($url);

$sxe = $document->getRootDataObject();$sxe = $document->getRootDataObject();

/* Check for number of results returned *//* Check for number of results returned */if (if ($sxe->totalResultsReturned$sxe->totalResultsReturned > 0) { > 0) {

/* Loop through results and print title, url and modification date *//* Loop through results and print title, url and modification date */ foreach ($sxe->Result AS $result) {foreach ($sxe->Result AS $result) { print 'Title: '.$result->Title."\n";print 'Title: '.$result->Title."\n"; print 'Url: '.$result->Url."\n";print 'Url: '.$result->Url."\n"; print 'Mod Date: '.date ('M d Y', print 'Mod Date: '.date ('M d Y', $result->ModificationDate$result->ModificationDate)."\n\n";)."\n\n"; }}}}

SDO: Consuming Yahoo ContextSearch SDO: Consuming Yahoo ContextSearch RESULTSRESULTS

Title: Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New?Title: Zend Technologies - PHP 5 In Depth - XML in PHP 5 - What's New?Url: http://www.zend.com/php5/articles/php5-xmlphp.phpUrl: http://www.zend.com/php5/articles/php5-xmlphp.phpMod Date: Feb 19 2007Mod Date: Feb 19 2007

Title: Zend Developer Zone | XML in PHP 5 - What's New?Title: Zend Developer Zone | XML in PHP 5 - What's New?Url: http://devzone.zend.com/node/view/id/1713Url: http://devzone.zend.com/node/view/id/1713Mod Date: Feb 26 2007Mod Date: Feb 26 2007

Title: Parsing XML using PHP5Title: Parsing XML using PHP5Url: http://www.developertutorials.com/tutorials/php/parsing-xml-using-Url: http://www.developertutorials.com/tutorials/php/parsing-xml-using-

php5-050816/page1.htmlphp5-050816/page1.htmlMod Date: Feb 02 2007Mod Date: Feb 02 2007

SDO: XML EditingSDO: XML Editingsdo/address.xsdsdo/address.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema"<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:addr="urn::addressNS" targetNamespace="urn::addressNS" xmlns:addr="urn::addressNS" targetNamespace="urn::addressNS" elementFormDefault="qualified">elementFormDefault="qualified">

<complexType name="AddressType"><complexType name="AddressType"> <sequence><sequence> <element name="street" type="string"/><element name="street" type="string"/> <element name="city" type="string"/><element name="city" type="string"/> <element name="state" type="string"/><element name="state" type="string"/> <element name="zip" type="string"/><element name="zip" type="string"/> </sequence></sequence> </complexType></complexType>

<element name="address" type="addr:AddressType" /><element name="address" type="addr:AddressType" /> </schema></schema>

SDO: XML EditingSDO: XML Editingsdo/editing.phpsdo/editing.php

$xmldas = SDO_DAS_XML::create("address.xsd");$xmldas = SDO_DAS_XML::create("address.xsd");$xdoc = $xmldas->createDocument();$xdoc = $xmldas->createDocument();$address = $xdoc->getRootDataObject();$address = $xdoc->getRootDataObject();

$address->street = "123 My Street";$address->street = "123 My Street";$address->zip = 12345;$address->zip = 12345;$address->state = 'ME';$address->state = 'ME';$address->city = 'Portland';$address->city = 'Portland';

print $xmldas->saveString($xdoc, 5);print $xmldas->saveString($xdoc, 5);

<?xml version="1.0" encoding="UTF-8"?><?xml version="1.0" encoding="UTF-8"?><address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="urn::addressNS" xmlns="urn::addressNS">xmlns:tns="urn::addressNS" xmlns="urn::addressNS"> <street>123 My Street</street><street>123 My Street</street> <city>Portland</city><city>Portland</city> <state>ME</state><state>ME</state> <zip>12345</zip><zip>12345</zip></address></address>

SDO: XML EditingSDO: XML Editingsdo/editing_error.phpsdo/editing_error.php

try {try { $xmldas = SDO_DAS_XML::create("address.xsd");$xmldas = SDO_DAS_XML::create("address.xsd"); $xdoc = $xmldas->createDocument("$xdoc = $xmldas->createDocument("addressaddress");"); $address = $xdoc->getRootDataObject();$address = $xdoc->getRootDataObject();

$address->city = "Portland";$address->city = "Portland"; $address->$address->companycompany = "Local Thunder"; = "Local Thunder"; print($xmldas->saveString($xdoc, 5));print($xmldas->saveString($xdoc, 5));} catch (SDO_Exception $e) {} catch (SDO_Exception $e) { print "Error: ".$e->getMessage()."\n";print "Error: ".$e->getMessage()."\n";}}

Error: Cannot find property:companyError: Cannot find property:company

DOMDOM

� Tree based parserTree based parser� Allows for creation and editing of XML documentsAllows for creation and editing of XML documents� W3C Specification with DOM Level 2/3 compliancyW3C Specification with DOM Level 2/3 compliancy� Provides XPath supportProvides XPath support� Provides XInclude SupportProvides XInclude Support� Ability to work with HTML documentsAbility to work with HTML documents� Zero copy interoperability with SimpleXMLZero copy interoperability with SimpleXML� Replacement for ext/domxml from PHP 4Replacement for ext/domxml from PHP 4

DOMNode ClassesDOMNode Classes� DOMDocumentDOMDocument� DOMElementDOMElement� DOMAttrDOMAttr� DOMCommentDOMComment� DOMDocumentTypeDOMDocumentType� DOMNotationDOMNotation� DOMEntityDOMEntity

� DOMEntityReferenceDOMEntityReference� DOMProcessingInstructionDOMProcessingInstruction� DOMNameSpaceNodeDOMNameSpaceNode� DOMDocumentFragmentDOMDocumentFragment� DOMCharacterDataDOMCharacterData� DOMTextDOMText� DOMCdataSectionDOMCdataSection

�DOMException�DOMImplementation

�DOMNodeList�DOMNamedNodeMap�DOMXPath

Additional Classes

DOM: Sample DocumentDOM: Sample Document<courses><courses> <course cid="c1"><course cid="c1"> <title>Basic Languages</title><title>Basic Languages</title> <description>Introduction to Languages</description><description>Introduction to Languages</description> <credits>1.5</credits><credits>1.5</credits> <lastmodified>2004-09-01T11:13:01</lastmodified><lastmodified>2004-09-01T11:13:01</lastmodified> </course></course> <course cid="c2"><course cid="c2"> <title>French I</title><title>French I</title> <description>Introduction to French</description><description>Introduction to French</description> <credits>3.0</credits><credits>3.0</credits> <lastmodified>2005-06-01T14:21:37</lastmodified><lastmodified>2005-06-01T14:21:37</lastmodified> </course></course> <course cid="c3"><course cid="c3"> <title>French II</title><title>French II</title> <description>Intermediate French</description><description>Intermediate French</description> <credits>3.0</credits><credits>3.0</credits> <lastmodified>2005-03-12T15:45:44</lastmodified><lastmodified>2005-03-12T15:45:44</lastmodified> </course></course></courses></courses>

DOM:Document NavigationDOM:Document Navigationdom/navigate-2.phpdom/navigate-2.php

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

DOM: Navigation OptimizedDOM: Navigation Optimizeddom/navigate-optimized.phpdom/navigate-optimized.php

function locateDescription($node) {function locateDescription($node) { while($node) {while($node) { if ($node->nodeType if ($node->nodeType == XML_ELEMENT_NODE &&== XML_ELEMENT_NODE && $node->nodeName $node->nodeName ==== 'description') { 'description') { $GLOBALS['arNodeSet'][] = $node;$GLOBALS['arNodeSet'][] = $node; return;return; }} locateDescription($node->firstChild);locateDescription($node->firstChild); $node = $node->nextSibling;$node = $node->nextSibling; }}}}

$dom = new DOMDocument();$dom = new DOMDocument();$dom->load('course.xml');$dom->load('course.xml');$root = $dom->documentElement;$root = $dom->documentElement;$arNodeSet = array();$arNodeSet = array();

locateDescription($root->firstChild);locateDescription($root->firstChild);

foreach ($arNodeSet AS $key=>$node) {foreach ($arNodeSet AS $key=>$node) { print "#$key: ".$node->nodeValue."\n";print "#$key: ".$node->nodeValue."\n";}}

DOM: Creating a Simple TreeDOM: Creating a Simple Treedom/create_simple_tree.phpdom/create_simple_tree.php

$doc = new DOMDocument();$doc = new DOMDocument();

$root = $doc->createElement("tree");$root = $doc->createElement("tree");$doc->appendChild($root);$doc->appendChild($root);

$root->setAttribute("att1", "att1 value");$root->setAttribute("att1", "att1 value");

$attr2 = $doc->createAttribute("att2");$attr2 = $doc->createAttribute("att2");$attr2->appendChild($doc->createTextNode("att2 value"));$attr2->appendChild($doc->createTextNode("att2 value"));$root->setAttributeNode($attr2);$root->setAttributeNode($attr2);

$child = $root->appendChild(new DOMElement("child"));$child = $root->appendChild(new DOMElement("child"));

$comment = $doc->createComment("My first Document");$comment = $doc->createComment("My first Document");$doc->insertBefore($comment, $root);$doc->insertBefore($comment, $root);

$pi = $doc->createProcessingInstruction("php", 'echo "Hello World!"');$pi = $doc->createProcessingInstruction("php", 'echo "Hello World!"');$root->appendChild($pi);$root->appendChild($pi);

$cdata = $doc->createCdataSection("special chars: & < > '");$cdata = $doc->createCdataSection("special chars: & < > '");$child->appendChild($cdata);$child->appendChild($cdata);

DOM: Simple Tree OutputDOM: 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>

DOM: ModificationDOM: ModificationLoad with User StreamLoad with User Stream

class MyStreamWrapper {class MyStreamWrapper { protected $stream = 'protected $stream = '<!--My first Document--><tree att1="att1 value" att2="att2 value"> <!--My first Document--><tree att1="att1 value" att2="att2 value">

<child><![CDATA[special chars: & < > ]]></child><?php echo "Hello World!"?></tree>';<child><![CDATA[special chars: & < > ]]></child><?php echo "Hello World!"?></tree>';

public function stream_open($path, $mode, $options, $opened_path) {public function stream_open($path, $mode, $options, $opened_path) { $this->position = 0;$this->position = 0; $this->len = strlen($this->stream);$this->len = strlen($this->stream); return true;return true; }}

public function stream_read($count) {public function stream_read($count) { $ret = substr($this->stream, $this->position, $count);$ret = substr($this->stream, $this->position, $count); $this->position += strlen($ret);$this->position += strlen($ret); return $ret;return $ret; }}

public function stream_close() { }public function stream_close() { } public function stream_eof() { return $this->position >= $this->len; }public function stream_eof() { return $this->position >= $this->len; } public function stream_stat() { return $this->len; }public function stream_stat() { return $this->len; } public function url_stat($path) { return array($this->len); }public function url_stat($path) { return array($this->len); }}}stream_wrapper_register('myStream', 'MyStreamWrapper');stream_wrapper_register('myStream', 'MyStreamWrapper');

DOM: Document ModificationDOM: Document Modificationdom/modify.phpdom/modify.php

<!--My first Document--><!--My first Document--><tree att1="att1 value" att2="att2 value"><child><![CDATA[special chars: & < > ]]></child><tree att1="att1 value" att2="att2 value"><child><![CDATA[special chars: & < > ]]></child><?php echo "Hello World!"?><?php echo "Hello World!"?></tree></tree>

$doc = new DOMDocument();$doc = new DOMDocument();$doc->load('myStream://myData');$doc->load('myStream://myData');$tree = $doc->documentElement;$tree = $doc->documentElement;

$tree->setAttribute("att1", "new val");$tree->setAttribute("att1", "new val");$tree->removeAttribute("att2");$tree->removeAttribute("att2");

foreach ($tree->childNodes AS $child) {foreach ($tree->childNodes AS $child) { if ($child->nodeName == 'child') {if ($child->nodeName == 'child') { $child->replaceChild(new DOMText("new Content"), $child->firstChild);$child->replaceChild(new DOMText("new Content"), $child->firstChild); break;break; }}}}

print $doc->saveXML();print $doc->saveXML();

<!--My first Document--><!--My first Document--><tree att1="new val"> <child>new Content</child><?php echo "Hello World!"?></tree><tree att1="new val"> <child>new Content</child><?php echo "Hello World!"?></tree>

DOM: Document ModificationDOM: Document Modification/* Remove all children of an element *//* Remove all children of an element */

while ($entry->hasChildNodes()) {while ($entry->hasChildNodes()) { $entry->removeChild($entry->firstChild);$entry->removeChild($entry->firstChild);}}

OROR

$node = $entry->lastChild;$node = $entry->lastChild;while($node) {while($node) { $prev = $node->previousSibling;$prev = $node->previousSibling; $entry->removeChild($node);$entry->removeChild($node); $node = $prev;$node = $prev;}}

/* This Will Not Work! *//* This Will Not Work! */foreach($entry->childNodes AS $node) {foreach($entry->childNodes AS $node) { $entry->removeChild($node);$entry->removeChild($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);

DOM and NamespacesDOM and Namespaces

<xsd:complexType <xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="ArrayOfint">name="ArrayOfint"> <xsd:complexContent><xsd:complexContent> <xsd:restriction base="soapenc:Array"><xsd:restriction base="soapenc:Array"> <xsd:attribute ref="soapenc:arrayType" <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[ ]"wsdl:arrayType="xsd:int[ ]"/>/> </xsd:restriction></xsd:restriction> </xsd:complexContent></xsd:complexContent></xsd:complexType></xsd:complexType>

Dom and NamepsacesDom and Namepsacesdom/namespace.phpdom/namespace.php

define("SCHEMA_NS", "http://www.w3.org/2001/XMLSchema");define("SCHEMA_NS", "http://www.w3.org/2001/XMLSchema");define("WSDL_NS", "http://schemas.xmlsoap.org/wsdl/");define("WSDL_NS", "http://schemas.xmlsoap.org/wsdl/");$dom = new DOMDocument();$dom = new DOMDocument();

$root = $dom->createElementNS(SCHEMA_NS, "xsd:complexType");$root = $dom->createElementNS(SCHEMA_NS, "xsd:complexType");$dom->appendChild($root);$dom->appendChild($root);

$root->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsdl", WSDL_NS);$root->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsdl", WSDL_NS);$root->setAttribute("name", "ArrayOfint");$root->setAttribute("name", "ArrayOfint");

$content = $root->appendChild($content = $root->appendChild(new DOMElement("xsd:complexContent", NULL, new DOMElement("xsd:complexContent", NULL, SCHEMA_NS)SCHEMA_NS)););

$restriction = $content->appendChild($restriction = $content->appendChild(new DOMElement("xsd:restriction", NULL, new DOMElement("xsd:restriction", NULL, SCHEMA_NS)SCHEMA_NS)););

$restriction->setAttribute("base", "soapenc:Array");$restriction->setAttribute("base", "soapenc:Array");

$attribute = $restriction->appendChild($attribute = $restriction->appendChild(new DOMElement("xsd:attribute", NULL, new DOMElement("xsd:attribute", NULL, SCHEMA_NS)SCHEMA_NS)););

$attribute->setAttribute("ref", "soapenc:arrayType");$attribute->setAttribute("ref", "soapenc:arrayType");

$attribute->setAttributeNS(WSDL_NS, "wsdl:arrayType ", "xsd:int[]");$attribute->setAttributeNS(WSDL_NS, "wsdl:arrayType ", "xsd:int[]");

DOM and XpathDOM and Xpathdom/xpath/dom-xpath.xmldom/xpath/dom-xpath.xml

<books xmlns="http://www.example.com/books"<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book">xmlns:bk="http://www.example.com/book"> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name><bk:name>Grapes of Wrath</bk:name> <bk:price>12.99</bk:price><bk:price>12.99</bk:price> </bk:book></bk:book>

<book qty="33" xmlns="http://www.example.com/ExteralClassics"><book qty="33" xmlns="http://www.example.com/ExteralClassics"> <name>To Kill a Mockingbird</name><name>To Kill a Mockingbird</name> <price>10.99</price><price>10.99</price> </book></book></books></books>

DOM and XpathDOM and Xpathdom/xpath/dom-xpath.phpdom/xpath/dom-xpath.php

<books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"><books xmlns="http://www.example.com/books" xmlns:bk="http://www.example.com/book"> <bk:book qty="25"><bk:book qty="25"> <bk:name>Grapes of Wrath</bk:name></bk:book><bk:name>Grapes of Wrath</bk:name></bk:book> <book qty="33" xmlns="http://www.example.com/ExteralClassics"><book qty="33" xmlns="http://www.example.com/ExteralClassics"> <name>To Kill a Mockingbird</name></book><name>To Kill a Mockingbird</name></book></books></books>

$xpath = $xpath = new DOMXPath($doc);new DOMXPath($doc);

$nodelist = $xpath->$nodelist = $xpath->queryquery("//bk:name");("//bk:name");print "Book Title: ".$nodelist->item($nodelist->length - 1)->textContent."\n";print "Book Title: ".$nodelist->item($nodelist->length - 1)->textContent."\n";

$inventory = $xpath->$inventory = $xpath->evaluateevaluate("sum(//@qty)");("sum(//@qty)");print "Total Books: ".$inventory."\n";print "Total Books: ".$inventory."\n";

$xpath->registerNameSpace("ec", "http://www.example.com/ExteralClassics");$xpath->registerNameSpace("ec", "http://www.example.com/ExteralClassics");$nodelist = $xpath->$nodelist = $xpath->queryquery("//ec:book");("//ec:book");

$book = $nodelist->item(0);$book = $nodelist->item(0);$inventory = $xpath->$inventory = $xpath->evaluateevaluate("sum(./@qty)", ("sum(./@qty)", $book$book););print "Total Books: ".$inventory."\n";print "Total Books: ".$inventory."\n";

DOM and Xpath ResultsDOM and Xpath ResultsBook Title: Grapes of WrathBook Title: Grapes of WrathTotal Books: 58Total Books: 58Total Books: 33Total Books: 33

Performing ValidationPerforming Validationdom/validation/validate.phpdom/validation/validate.php

$doc = new DOMDocument();$doc = new DOMDocument();print "DTD Validation:\n";print "DTD Validation:\n";$doc->load('courses-dtd.xml', LIBXML_DTDVALID);$doc->load('courses-dtd.xml', LIBXML_DTDVALID);/* No errors means document is valid *//* No errors means document is valid */

if ($doc->validate()) { print " Document Is Valid\n"; }if ($doc->validate()) { print " Document Is Valid\n"; }

print "DTD Validation FAILURE:\n";print "DTD Validation FAILURE:\n";$doc->load('course-id.xml');$doc->load('course-id.xml');if (if ($doc->validate()$doc->validate()) { print " Document Is Valid\n"; }) { print " Document Is Valid\n"; }

$doc->load('course.xml');$doc->load('course.xml');print "\nXML Schema Validation:\n";print "\nXML Schema Validation:\n";if (if ($doc->schemaValidate('course.xsd')$doc->schemaValidate('course.xsd')) { print " Document is valid\n"; }) { print " Document is valid\n"; }

$doc->load('course.xml');$doc->load('course.xml');print "\nRelaxNG Validation:\n";print "\nRelaxNG Validation:\n";if (if ($doc->relaxNGValidate('course.rng')$doc->relaxNGValidate('course.rng')) { print " Document is valid\n"; ) { print " Document is valid\n";

} }

Performing Validation ResultsPerforming Validation ResultsDTD Validation:DTD Validation: Document Is ValidDocument Is Valid

DTD Validation FAILURE:DTD Validation FAILURE:Warning: DOMDocument::validate(): No declaration for element courses in Warning: DOMDocument::validate(): No declaration for element courses in

/home/rrichards/workshop/dom/validation/validate.php on line 11/home/rrichards/workshop/dom/validation/validate.php on line 11Warning: DOMDocument::validate(): No declaration for element course in Warning: DOMDocument::validate(): No declaration for element course in

/home/rrichards/workshop/dom/validation/validate.php on line 11/home/rrichards/workshop/dom/validation/validate.php on line 11Warning: DOMDocument::validate(): No declaration for element title in Warning: DOMDocument::validate(): No declaration for element title in

/home/rrichards/workshop/dom/validation/validate.php on line 11/home/rrichards/workshop/dom/validation/validate.php on line 11. . .. . .

XML Schema Validation:XML Schema Validation: Document is validDocument is valid

RelaxNG Validation:RelaxNG Validation: Document is validDocument is valid

Extending DOM ClassesExtending DOM Classes

� Overriding the constructor requires the parent Overriding the constructor requires the parent constructor to be called.constructor to be called.

� Properties built into the DOM classes cannot Properties built into the DOM classes cannot be overridden.be overridden.

� Methods built into the DOM classes may can Methods built into the DOM classes may can be overridden.be overridden.

� The lifespan of an extended object is that of The lifespan of an extended object is that of the object itself.the object itself.

Extending DOM Classes Extending DOM Classes dom/extending/dom/extending/extending.phpextending.php

class customElement extends DOMElement { }class customElement extends DOMElement { }

class customDoc extends DOMDocument {class customDoc extends DOMDocument { public $nodeName = "customDoc";public $nodeName = "customDoc";

function __construct($rootName) {function __construct($rootName) { parent::__construct();parent::__construct(); if (! empty($rootName))if (! empty($rootName)) $element = $this->appendChild(new DOMElement($rootName));$element = $this->appendChild(new DOMElement($rootName)); }}

function createElement($name, $value, $parent=NULL) {function createElement($name, $value, $parent=NULL) { $custom = new customElement($name, $value);$custom = new customElement($name, $value); if ($parent && ($parent instanceof DOMElement)) { if ($parent && ($parent instanceof DOMElement)) { $parent->appendChild($custom); }$parent->appendChild($custom); } return $custom;return $custom; }}}}

$myc = new customDoc("root");$myc = new customDoc("root");$myelement = $myc->createElement("myname", "value", $myc->documentElement);$myelement = $myc->createElement("myname", "value", $myc->documentElement);if ($myelement instanceof customElement) { print "This is a customElement\n"; }if ($myelement instanceof customElement) { print "This is a customElement\n"; }

print $myc->nodeName."\n";print $myc->nodeName."\n";print $myc->saveXML();print $myc->saveXML();

DOM Object ScopeDOM Object Scopedom/extending/object_scope.phpdom/extending/object_scope.php

class customElement extends DOMElement { }class customElement extends DOMElement { }

function changeit($doc) {function changeit($doc) { $myelement$myelement = new customElement("custom", "element2"); = new customElement("custom", "element2");

$doc->replaceChild($myelement, $doc->documentElement);$doc->replaceChild($myelement, $doc->documentElement);print "Within changeit function: ".get_class($doc->documentElement)."\n";print "Within changeit function: ".get_class($doc->documentElement)."\n";

}}

$doc = new DOMDocument();$doc = new DOMDocument();

$myelement$myelement = $doc->appendChild(new customElement("custom", "element")); = $doc->appendChild(new customElement("custom", "element"));print "After Append: ".get_class($myelement)."\n";print "After Append: ".get_class($myelement)."\n";

unset($myelement);unset($myelement);print "After unset: ".get_class($doc->documentElement)."\n";print "After unset: ".get_class($doc->documentElement)."\n";

changeit($doc);changeit($doc);print "Outside changeit(): ".get_class($doc->documentElement)."\n";print "Outside changeit(): ".get_class($doc->documentElement)."\n";

After Append: customElementAfter Append: customElementAfter unset: DOMElementAfter unset: DOMElementWithin changeit function: customElementWithin changeit function: customElementOutside changeit(): DOMElementOutside changeit(): DOMElement

DOM: registerNodeClassDOM: registerNodeClass dom/extending/register_node_class.php dom/extending/register_node_class.php

class customElement extends DOMElement { }class customElement extends DOMElement { }function changeit($doc) {function changeit($doc) { $myelement$myelement = new DOMElement("custom", "element2"); = new DOMElement("custom", "element2");

$doc->replaceChild($myelement, $doc->documentElement);$doc->replaceChild($myelement, $doc->documentElement);print "Within changeit function: ".get_class($doc->documentElement)."\n";print "Within changeit function: ".get_class($doc->documentElement)."\n";

}}

$doc = new DOMDocument();$doc = new DOMDocument();$doc->registerNodeClass('DOMElement', 'customElement');$doc->registerNodeClass('DOMElement', 'customElement');

$myelement$myelement = $doc->appendChild($doc->createElement("custom", "element")); = $doc->appendChild($doc->createElement("custom", "element"));print "After Append: ".get_class($myelement)."\n";print "After Append: ".get_class($myelement)."\n";

unset($myelement);unset($myelement);print "After unset: ".get_class($doc->documentElement)."\n";print "After unset: ".get_class($doc->documentElement)."\n";

changeit($doc);changeit($doc);print "Outside changeit(): ".get_class($doc->documentElement)."\n";print "Outside changeit(): ".get_class($doc->documentElement)."\n";

After Append: customElementAfter Append: customElementAfter unset: customElementAfter unset: customElementWithin changeit function: DOMElementWithin changeit function: DOMElementOutside changeit(): customElementOutside changeit(): customElement

DOM:Common IssuesDOM:Common Issues

� DOM Objects and SessionsDOM Objects and Sessions� Removing Nodes while iterating a Nodeset skips Removing Nodes while iterating a Nodeset skips

nodesnodes� XML Tree contains garbled charactersXML Tree contains garbled characters� Extended class is not returned from property or Extended class is not returned from property or

methodmethod� Elements not being returned by IDElements not being returned by ID� Entity errors are issues when loading a documentEntity errors are issues when loading a document� New DTD is not recognized by documentNew DTD is not recognized by document

XMLReaderXMLReader

� Forward moving stream based parserForward moving stream based parser� It is a Pull parserIt is a Pull parser� Based on the C# XmlTextReader APIBased on the C# XmlTextReader API� Advantages:Advantages:

� Low memory footprintLow memory footprint� Namespace supportNamespace support� Simple APISimple API� Validation supportValidation support� Advanced Feature SetAdvanced Feature Set� Faster ProcessingFaster Processing

XMLReader: Simple ExampleXMLReader: Simple Examplexmlreader/reader_simple.xmlxmlreader/reader_simple.xml

<?xml version='1.0'?><?xml version='1.0'?><chapter xmlns:a="http://www.example.com/namespace-a"<chapter xmlns:a="http://www.example.com/namespace-a" xmlns="http://www.example.com/default">xmlns="http://www.example.com/default"> <a:title>XMLReader</a:title><a:title>XMLReader</a:title> <para><para> First ParagraphFirst Paragraph </para></para> <a:section a:id="about"><a:section a:id="about"> <title>About this Document</title><title>About this Document</title> <para><para> <!-- this is a comment --><!-- this is a comment --> <?php echo 'Hi! This is PHP version ' . phpversion(); ?><?php echo 'Hi! This is PHP version ' . phpversion(); ?> </para></para> </a:section></a:section></chapter></chapter>

XMLReader: Simple ExampleXMLReader: Simple Examplexmlreader/reader_simple.phpxmlreader/reader_simple.php

$reader = new XMLReader();$reader = new XMLReader();$reader->open('reader_simple.xml');$reader->open('reader_simple.xml');$reader->read();$reader->read();

print "xmlns Attribute value: ".$reader->getAttributeNo(0)."\n\n";print "xmlns Attribute value: ".$reader->getAttributeNo(0)."\n\n";

while ($reader->read() && $reader->name != "a:title") { }while ($reader->read() && $reader->name != "a:title") { }print "Local Name for Element: ".$reader->localName."\n";print "Local Name for Element: ".$reader->localName."\n";print "Namespace URI for Element: ".$reader->namespaceURI."\n";print "Namespace URI for Element: ".$reader->namespaceURI."\n";

while($reader->read()) {while($reader->read()) { switch ($reader->nodeType) {switch ($reader->nodeType) { case XMLReader::ELEMENT:case XMLReader::ELEMENT: print "Element: ".$reader->name."\n";print "Element: ".$reader->name."\n"; if ($reader->hasAttributes && $reader->moveToFirstAttribute()) {if ($reader->hasAttributes && $reader->moveToFirstAttribute()) { do {do { print " ".$reader->name."=".$reader->value."\n";print " ".$reader->name."=".$reader->value."\n"; } while($reader->moveToNextAttribute());} while($reader->moveToNextAttribute()); }} break;break; case XMLReader::PI:case XMLReader::PI: print "PI Target: ".$reader->name."\n PI Data: ".$reader->value."\n";print "PI Target: ".$reader->name."\n PI Data: ".$reader->value."\n"; }}}}

XMLReader: Simple ExampleXMLReader: Simple ExampleRESULTSRESULTS

xmlns Attribute value: http://www.example.com/namespace-axmlns Attribute value: http://www.example.com/namespace-a

Local Name for Element: titleLocal Name for Element: titleNamespace URI for Element: Namespace URI for Element: http://www.example.com/namespace-ahttp://www.example.com/namespace-a

Element: paraElement: paraElement: a:sectionElement: a:section a:id=abouta:id=aboutElement: titleElement: titleElement: paraElement: paraPI Target: phpPI Target: php PI Data: echo 'Hi! This is PHP version ' . phpversion(); PI Data: echo 'Hi! This is PHP version ' . phpversion();

XMLReader: Consuming Yahoo XMLReader: Consuming Yahoo ShoppingShopping

<?xml version="1.0" encoding="ISO-8859-1"?><?xml version="1.0" encoding="ISO-8859-1"?><ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="urn:yahoo:prods" xmlns="urn:yahoo:prods" xsi:schemaLocation="urn:yahoo:prods xsi:schemaLocation="urn:yahoo:prods

http://api.shopping.yahoo.com/shoppingservice/v1/productsearch.xsd" http://api.shopping.yahoo.com/shoppingservice/v1/productsearch.xsd" totalResultsAvailable="8850" firstResultPosition="2" totalResultsReturned="2">totalResultsAvailable="8850" firstResultPosition="2" totalResultsReturned="2">

<<ResultResult>> <<CatalogCatalog ID="1991433722"> ID="1991433722"> <<UrlUrl ><![CDATA[http://shopping.yahoo.com/p:Linksys. . .2]]></Url>><![CDATA[http://shopping.yahoo.com/p:Linksys. . .2]]></Url> <<ProductNameProductName><![CDATA[Linksys WRT5. . .r Broadband ><![CDATA[Linksys WRT5. . .r Broadband

Router]]></ProductName>Router]]></ProductName> <<PriceFromPriceFrom>69.97</PriceFrom>>69.97</PriceFrom> <<PriceToPriceTo>89.99</PriceTo>>89.99</PriceTo> <Thumbnail /><!-- child elements Url (CDATA), Height, Width --><Thumbnail /><!-- child elements Url (CDATA), Height, Width --> <<DescriptionDescription><![CDATA[The Wireless-G . . .ces.]]></Description>><![CDATA[The Wireless-G . . .ces.]]></Description> <Summary><![CDATA[IEEE 802.3, ...]]></Summary><Summary><![CDATA[IEEE 802.3, ...]]></Summary> <UserRating /><!-- Rating sub elements --><UserRating /><!-- Rating sub elements --> <SpecificationList /><!-- 0+ Specification child elements --></SpecificationList><SpecificationList /><!-- 0+ Specification child elements --></SpecificationList> </Catalog></Catalog> </Result></Result></ResultSet></ResultSet>

XMLReader: Consuming Yahoo ShoppingXMLReader: Consuming Yahoo Shoppingxmlreader/rest_yahoo_shopping.phpxmlreader/rest_yahoo_shopping.php

function getTextValue($reader) { ... }function getTextValue($reader) { ... }function processCatalog($reader) { ... }function processCatalog($reader) { ... }function processResult($reader) { ... }function processResult($reader) { ... }

/* URL to Product Search service *//* URL to Product Search service */$url = 'http://api.shopping.yahoo.com/ShoppingService/V1/productSearch';$url = 'http://api.shopping.yahoo.com/ShoppingService/V1/productSearch';

/* The query is separate here as the terms must be encoded. *//* The query is separate here as the terms must be encoded. */$url .= '?query='.rawurlencode('linksys');$url .= '?query='.rawurlencode('linksys');

/* Complete the URL with App ID, limit to 1 result and start at second record *//* Complete the URL with App ID, limit to 1 result and start at second record */$url .= "&appid=zzz&results=2&start=2";$url .= "&appid=zzz&results=2&start=2";

$reader = new XMLReader();$reader = new XMLReader();

if (! $reader->open($url)) { print "Cannot access Webservice\n"; exit; }if (! $reader->open($url)) { print "Cannot access Webservice\n"; exit; }

while($reader->name != "Result") { $reader->read(); }while($reader->name != "Result") { $reader->read(); }do {do { processResult($reader);processResult($reader);} while($reader->next('Result'));} while($reader->next('Result'));

XMLReader: Consuming Yahoo ShoppingXMLReader: Consuming Yahoo Shoppingxmlreader/rest_yahoo_shopping.phpxmlreader/rest_yahoo_shopping.php

function getTextValue($reader) {function getTextValue($reader) { if ($reader->nodeType != if ($reader->nodeType != XMLReader::ELEMENTXMLReader::ELEMENT || $reader->isEmptyElement || $reader->isEmptyElement || ($reader->read() && $reader->nodeType == || ($reader->read() && $reader->nodeType == XMLReader::END_ELEMENTXMLReader::END_ELEMENT)))) return;return; $retVal = $reader->value;$retVal = $reader->value; $reader->read();$reader->read(); return $retVal;return $retVal;}}

function processResult($reader) {function processResult($reader) { $depth = $reader->depth;$depth = $reader->depth; if ($reader->isEmptyElement || ($reader->read() && if ($reader->isEmptyElement || ($reader->read() && $reader->nodeType == $reader->nodeType == XMLReader::END_ELEMENTXMLReader::END_ELEMENT)))) return;return;

while($depth < $reader->depth && $reader->name != "Catalog") { $reader->read(); while($depth < $reader->depth && $reader->name != "Catalog") { $reader->read(); };};processCatalog($reader);processCatalog($reader);/* Read until </Result> is encountered *//* Read until </Result> is encountered */while($depth < $reader->depth) { $reader->read(); }while($depth < $reader->depth) { $reader->read(); }

}}

XMLReader: Consuming Yahoo ShoppingXMLReader: Consuming Yahoo Shoppingxmlreader/rest_yahoo_shopping.phpxmlreader/rest_yahoo_shopping.php

function processCatalog($reader) {function processCatalog($reader) { $depth = $reader->depth;$depth = $reader->depth; print "Catalog ID".$reader->getAttribute('ID')."\n";print "Catalog ID".$reader->getAttribute('ID')."\n";

if ($reader->isEmptyElement || ($reader->read() && if ($reader->isEmptyElement || ($reader->read() && $reader->nodeType == $reader->nodeType == XMLReader::END_ELEMENTXMLReader::END_ELEMENT)))) return;return; while($depth < $reader->depth) {while($depth < $reader->depth) { switch ($reader->name) {switch ($reader->name) { case "ProductName":case "ProductName": case "PriceFrom":case "PriceFrom": case "PriceTo":case "PriceTo": case "Description":case "Description": case "Url":case "Url":

print $reader->name.": ".getTextValue($reader)."\n";print $reader->name.": ".getTextValue($reader)."\n"; }} $reader->next();$reader->next(); }}}}

XMLReader: Consuming Yahoo ShoppingXMLReader: Consuming Yahoo ShoppingRESULTS (Abbreviated)RESULTS (Abbreviated)

Catalog ID1990338714Catalog ID1990338714Url: Url:

http://shopping.yahoo.com/p:Linksys%20Instant%20Broadband%20Etherhttp://shopping.yahoo.com/p:Linksys%20Instant%20Broadband%20EtherFast%20Cable%2FDSL%20Router:1990338714Fast%20Cable%2FDSL%20Router:1990338714

ProductName: Linksys Instant Broadband EtherFast Cable/DSL RouterProductName: Linksys Instant Broadband EtherFast Cable/DSL RouterPriceFrom: 39.99PriceFrom: 39.99PriceTo: 72.71PriceTo: 72.71Description: <P>Linksys, a provider of networking hardware for the Description: <P>Linksys, a provider of networking hardware for the

small/medium business (SMB), small office/home office (SOHO), and small/medium business (SMB), small office/home office (SOHO), and enterprise markets and broadband networking hardware for the home, has enterprise markets and broadband networking hardware for the home, has announced the new EtherFast Cable/DSL Router. The first in the new announced the new EtherFast Cable/DSL Router. The first in the new Instant Broadband series, this Linksys broadband router will enable home Instant Broadband series, this Linksys broadband router will enable home or office users to connect their computers to a cable or DSL modem and 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 securely share Internet access and perform networking tasks such as file and printer sharing. The built-in hardware firewall gives users the security and printer sharing. The built-in hardware firewall gives users the security of sharing files without fear of intruders hacking into the network. </P>of sharing files without fear of intruders hacking into the network. </P>

XMLReader: DTD ValidationXMLReader: DTD Validationxmlreader/validation/reader.xmlxmlreader/validation/reader.xml

<!DOCTYPE chapter [<!DOCTYPE chapter [<!ELEMENT chapter (title, para, section)><!ELEMENT chapter (title, para, section)><!ELEMENT title (#PCDATA)><!ELEMENT title (#PCDATA)><!ELEMENT para ANY><!ELEMENT para ANY><!ATTLIST para name CDATA "default"><!ATTLIST para name CDATA "default"><!ELEMENT section (#PCDATA)><!ELEMENT section (#PCDATA)><!ATTLIST section id ID #REQUIRED><!ATTLIST section id ID #REQUIRED>]>]><chapter><chapter> <title>XMLReader</title><title>XMLReader</title> <para><para> First ParagraphFirst Paragraph </para></para> <section id="about"><section id="about"> <title>About this Document</title><title>About this Document</title> <para>content</para><para>content</para> </section></section></chapter></chapter>

XMLReader: DTD ValidationXMLReader: DTD Validationxmlreader/validation/reader.phpxmlreader/validation/reader.php

$objReader = XMLReader::open('reader.xml');$objReader = XMLReader::open('reader.xml');$objReader->setParserProperty(XMLReader::VALIDATE, TRUE);$objReader->setParserProperty(XMLReader::VALIDATE, TRUE);

/* As of PHP 5.2 LIBXML Parser Options may be passed *//* As of PHP 5.2 LIBXML Parser Options may be passed */// $objReader = XMLReader::open('reader.xml', NULL,// $objReader = XMLReader::open('reader.xml', NULL, LIBXML_DTDVALID);LIBXML_DTDVALID);

libxml_use_internal_errors(TRUE);libxml_use_internal_errors(TRUE);

while ($objReader->read()) {while ($objReader->read()) { if (if ( ! $objReader->isValid()! $objReader->isValid()) {) { print "NOT VALID\n";print "NOT VALID\n"; break;break; }}}}

$arErrors = libxml_get_errors();$arErrors = libxml_get_errors();foreach ($arErrors AS $xmlError) {foreach ($arErrors AS $xmlError) { print $xmlError->message;print $xmlError->message;}}

XMLReader: DTD ValidationXMLReader: DTD ValidationRESULTSRESULTS

PHP Strict Standards: Non-static method XMLReader::open() should not be PHP Strict Standards: Non-static method XMLReader::open() should not be called statically in /home/rrichards/workshop/xmlreader/validation/reader.php called statically in /home/rrichards/workshop/xmlreader/validation/reader.php on line 2on line 2

NOT VALIDNOT VALIDElement section was declared #PCDATA but contains non Element section was declared #PCDATA but contains non text nodestext nodes

XMLReader: Relax NG ValidationXMLReader: Relax NG Validationxmlreader/validation/reader.rngxmlreader/validation/reader.rng

<?xml version="1.0" encoding="utf-8" ?><?xml version="1.0" encoding="utf-8" ?><element name="chapter" <element name="chapter" xmlns="http://relaxng.org/ns/structure/1.0">xmlns="http://relaxng.org/ns/structure/1.0"> <element name="title"><element name="title"> <text/><text/> </element></element> <element name="para"><element name="para"> <text/><text/> </element></element> <element name="section"><element name="section"> <attribute name="id" /><attribute name="id" /> <text/><text/> </element></element></element></element>

XMLReader: Relax NG ValidationXMLReader: Relax NG Validationxmlreader/validation/reader-rng.phpxmlreader/validation/reader-rng.php

$objReader = XMLReader::open('reader.xml');$objReader = XMLReader::open('reader.xml');$objReader->setRelaxNGSchema('reader.rng');$objReader->setRelaxNGSchema('reader.rng');

libxml_use_internal_errors(TRUE);libxml_use_internal_errors(TRUE);

while ($objReader->read()) {while ($objReader->read()) { if (if ( ! $objReader->isValid()! $objReader->isValid()) {) { print "NOT VALID\n";print "NOT VALID\n"; break;break; }}}}

$arErrors = libxml_get_errors();$arErrors = libxml_get_errors();foreach ($arErrors AS $xmlError) {foreach ($arErrors AS $xmlError) { print $xmlError->message;print $xmlError->message;}}

XMLReader: Relax NG ValidationXMLReader: Relax NG Validation RESULTSRESULTS

PHP Strict Standards: Non-static method XMLReader::open() should not be PHP Strict Standards: Non-static method XMLReader::open() should not be called statically in /home/rrichards/workshop/xmlreader/validation/reader.php called statically in /home/rrichards/workshop/xmlreader/validation/reader.php on line 2on line 2

NOT VALIDNOT VALIDDid not expect element title thereDid not expect element title there

XMLReader: XML Schema ValidationXMLReader: XML Schema Validationxmlreader/validation/reader.xsdxmlreader/validation/reader.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="chapter"><xsd:element name="chapter"> <xsd:complexType><xsd:complexType> <xsd:sequence><xsd:sequence> <xsd:element name="title" type="xsd:string"/><xsd:element name="title" type="xsd:string"/> <xsd:element name="para" type="xsd:string"/><xsd:element name="para" type="xsd:string"/> <xsd:element name="section"><xsd:element name="section"> <xsd:complexType><xsd:complexType> <xsd:simpleContent><xsd:simpleContent> <xsd:extension base="xsd:string"><xsd:extension base="xsd:string"> <xsd:attribute name="id" type="xsd:ID"/><xsd:attribute name="id" type="xsd:ID"/> </xsd:extension></xsd:extension> </xsd:simpleContent></xsd:simpleContent> </xsd:complexType></xsd:complexType> </xsd:element></xsd:element> </xsd:sequence></xsd:sequence> </xsd:complexType></xsd:complexType> </xsd:element></xsd:element></xsd:schema></xsd:schema>

XMLReader: XML Schema ValidationXMLReader: XML Schema Validationxmlreader/validation/reader-xsd.phpxmlreader/validation/reader-xsd.php

$objReader = XMLReader::open('reader.xml');$objReader = XMLReader::open('reader.xml');$objReader->setSchema('reader.xsd');$objReader->setSchema('reader.xsd');

libxml_use_internal_errors(TRUE);libxml_use_internal_errors(TRUE);

while ($objReader->read()) {while ($objReader->read()) { if (if ( ! $objReader->isValid()! $objReader->isValid()) {) { print "NOT VALID\n";print "NOT VALID\n"; break;break; }}}}

$arErrors = libxml_get_errors();$arErrors = libxml_get_errors();foreach ($arErrors AS $xmlError) {foreach ($arErrors AS $xmlError) { print $xmlError->message;print $xmlError->message;}}

LIBXML2-2.20+ REQUIREDLIBXML2-2.20+ REQUIRED

XMLReader: XML Schema ValidationXMLReader: XML Schema Validation RESULTSRESULTS

PHP Strict Standards: Non-static method XMLReader::open() should not be PHP Strict Standards: Non-static method XMLReader::open() should not be called statically in /home/rrichards/workshop/xmlreader/validation/reader.php called statically in /home/rrichards/workshop/xmlreader/validation/reader.php on line 2on line 2

NOT VALIDNOT VALIDElement 'para', attribute 'name': The attribute 'name' is not Element 'para', attribute 'name': The attribute 'name' is not allowed.allowed.Element 'section': Element content is not allowed, because Element 'section': Element content is not allowed, because the content type is a simple type definition.the content type is a simple type definition.

Tree ParsersTree Parsers

� Pros:Pros:� Full navigation and modification of the XML Full navigation and modification of the XML

documentdocument� Navigating and searching are extremely fast once Navigating and searching are extremely fast once

the tree is loaded into memorythe tree is loaded into memory

� Cons:Cons:� Must wait until entire tree is loaded to begin Must wait until entire tree is loaded to begin

working with the XML.working with the XML.� Memory intensiveMemory intensive

Streaming ParsersStreaming Parsers

� Pros:Pros:� Uses minimal memoryUses minimal memory� Processing takes place immediately while the Processing takes place immediately while the

document is parseddocument is parsed

� Cons:Cons:� Minimal to no navigation support (forward only)Minimal to no navigation support (forward only)� No document editing capabilitiesNo document editing capabilities

Raw Test DataRaw Test Data<books><books> <book id="1"><title>1</title><pages>1</pages></book><book id="1"><title>1</title><pages>1</pages></book> <book id="2"><title>2</title><pages>2</pages></book><book id="2"><title>2</title><pages>2</pages></book> <!-- Remaining book elements for a total of 200,000 --><!-- Remaining book elements for a total of 200,000 --></books></books>

Memory Usage:Memory Usage:

177KB26KB85.6MB85.6MB

XMLReaderext/xmlSimpleXMLDOM

0.2380.9306.5836.623

XMLReaderext/xmlSimpleXMLDOM

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:

XMLWriterXMLWriter

� Lightweight and forward-only API for Lightweight and forward-only API for generating well formed XMLgenerating well formed XML

� Automatically escapes dataAutomatically escapes data� Works with PHP 4.3+ available at Works with PHP 4.3+ available at

http://pecl.php.net/package/xmlwriterhttp://pecl.php.net/package/xmlwriter� Object Oriented API available for PHP 5+Object Oriented API available for PHP 5+� Part of core PHP distribution since PHP 5.1.2Part of core PHP distribution since PHP 5.1.2

XMLWriter: Simple ExampleXMLWriter: Simple Examplexmlwriter/simple.phpxmlwriter/simple.php

<?php<?php$xw = new XMLWriter();$xw = new XMLWriter();$xw->openMemory();$xw->openMemory();

/* Turn on indenting to make output look pretty and set string /* Turn on indenting to make output look pretty and set string used for indenting as teh default space is too short*/used for indenting as teh default space is too short*/$xw->setIndent(TRUE);$xw->setIndent(TRUE);$xw->setIndentString(' ');$xw->setIndentString(' ');

/* Write out the optional XML declaration only specifying version *//* Write out the optional XML declaration only specifying version */$xw->startDocument('1.0');$xw->startDocument('1.0');

/* Create the opening document element, which is namespaced *//* Create the opening document element, which is namespaced */$xw->startElementNs(NULL, "chapter", "http://www.example.com/default");$xw->startElementNs(NULL, "chapter", "http://www.example.com/default");

/* Write out an xml namespace declaration that is used later in the document *//* Write out an xml namespace declaration that is used later in the document */$res = $xw->writeAttribute('xmlns:a', 'http://www.example.com/namespace-a');$res = $xw->writeAttribute('xmlns:a', 'http://www.example.com/namespace-a');

/* Write complete elements with text content *//* Write complete elements with text content */$xw->writeElement('a:title', 'XMLReader');$xw->writeElement('a:title', 'XMLReader');$xw->writeElement('para', 'spec chars < > & " inside para element');$xw->writeElement('para', 'spec chars < > & " inside para element');

XMLWriter: Simple ExampleXMLWriter: Simple Examplexmlwriter/simple.phpxmlwriter/simple.php

/* start an element and add an attribute to it *//* start an element and add an attribute to it */$xw->startElement('a:section');$xw->startElement('a:section');$xw->writeAttribute('a:id', 'about');$xw->writeAttribute('a:id', 'about');

/* Write out an element with special characters *//* Write out an element with special characters */$xw->writeElement('title', 'Pro PHP XML & Webservices');$xw->writeElement('title', 'Pro PHP XML & Webservices');

$xw->startElement('para'); /* This opens the para element */$xw->startElement('para'); /* This opens the para element */

$xw->writeComment("this is a comment");$xw->writeComment("this is a comment");$xw->text(" ");$xw->text(" ");$xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); ");$xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); ");$xw->text("\n ");$xw->text("\n ");

$xw->endElement(); /* This will close the open para element */$xw->endElement(); /* This will close the open para element */

$xw->endDocument();$xw->endDocument();

/* Flush and clear the buffer *//* Flush and clear the buffer */echo $xw->flush(true);echo $xw->flush(true);?>?>

XMLWriter: Simple ExampleXMLWriter: Simple Examplexmlwriter/simple.phpxmlwriter/simple.php

/* start an element and add an attribute to it *//* start an element and add an attribute to it */$xw->startElement('a:section');$xw->startElement('a:section');$xw->writeAttribute('a:id', 'about');$xw->writeAttribute('a:id', 'about');

/* Write out an element with special characters *//* Write out an element with special characters */$xw->writeElement('title', 'Pro PHP XML & Webservices');$xw->writeElement('title', 'Pro PHP XML & Webservices');

$xw->startElement('para'); /* This opens the para element */$xw->startElement('para'); /* This opens the para element */

$xw->writeComment("this is a comment");$xw->writeComment("this is a comment");$xw->text(" ");$xw->text(" ");$xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); ");$xw->writePi("php", "echo 'Hi! This is PHP version ' . phpversion(); ");$xw->text("\n ");$xw->text("\n ");

$xw->endElement(); /* This will close the open para element */$xw->endElement(); /* This will close the open para element */

$xw->endDocument();$xw->endDocument();

/* Flush and clear the buffer *//* Flush and clear the buffer */echo $xw->flush(true);echo $xw->flush(true);?>?>

XMLWriter: Simple ExampleXMLWriter: Simple ExampleResultsResults

<?xml version="1.0"?><?xml version="1.0"?><chapter xmlns="http://www.example.com/default"<chapter xmlns="http://www.example.com/default" xmlns:a="http://www.example.com/namespace-a">xmlns:a="http://www.example.com/namespace-a"> <a:title>XMLReader</a:title><a:title>XMLReader</a:title> <para>spec chars &lt; &gt; &amp; &quot; inside para <para>spec chars &lt; &gt; &amp; &quot; inside para element</para>element</para> <a:section a:id="about"><a:section a:id="about"> <title>Pro PHP XML &amp; Webservices</title><title>Pro PHP XML &amp; Webservices</title> <para><para> <!--this is a comment--><!--this is a comment--> <?php echo 'Hi! This is PHP version ' . phpversion(); ?><?php echo 'Hi! This is PHP version ' . phpversion(); ?> </para></para> </a:section></a:section></chapter></chapter>

XSLXSL� Used to transform XML dataUsed to transform XML data� XSLT based on XPathXSLT based on XPath� Works with DOM and SimpleXML, although the Works with DOM and SimpleXML, although the

DOM extension is required.DOM extension is required.� Provides the capability of calling PHP functions Provides the capability of calling PHP functions

during a transformationduring a transformation� DOM nodes may be returned from PHP functionsDOM nodes may be returned from PHP functions� The LIBXML_NOCDATA and LIBXML_NOENT The LIBXML_NOCDATA and LIBXML_NOENT

constants are your friends.constants are your friends.� libxslt 1.1.5+ is recommended to avoid problems libxslt 1.1.5+ is recommended to avoid problems

when using xsl:keywhen using xsl:key

XSL: XML Input Data XSL: XML Input Data xsl/sites.xmlxsl/sites.xml

<?xml version="1.0"?><?xml version="1.0"?><sites><sites> <site xml:id="php-gen"><site xml:id="php-gen"> <name>PHP General</name><name>PHP General</name> <url>http://news.php.net/group.php?group=php.general&amp;format=rss</url><url>http://news.php.net/group.php?group=php.general&amp;format=rss</url> </site></site> <site xml:id="php-pear"><site xml:id="php-pear"> <name>PHP Pear Dev</name><name>PHP Pear Dev</name> <url>http://news.php.net/group.php?group=php.pear.dev&amp;format=rss</url><url>http://news.php.net/group.php?group=php.pear.dev&amp;format=rss</url> </site></site> <site xml:id="php-planet"><site xml:id="php-planet"> <name>Planet PHP</name><name>Planet PHP</name> <url>http://www.planet-php.org/rss/</url><url>http://www.planet-php.org/rss/</url> </site></site></sites></sites>

XSL: Simple TransformationXSL: Simple Transformationxsl/simple_stylesheet.xslxsl/simple_stylesheet.xsl

<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 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:template></xsl:stylesheet>

XSL: Simple TransformationXSL: Simple Transformationxsl/simple_stylesheet.phpxsl/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);

XSL: Simple TransformationXSL: Simple TransformationRESULTSRESULTS

<html> <body> <p>PHP General : http://news.php.net/group.php?group=php.general&format=rss</p> <p>PHP Pear Dev : http://news.php.net/group.php?group=php.pear.dev&format=rss</p> <p>Planet PHP : http://www.planet-php.org/rss/</p> </body></html>

XSL: Advanced TransformationXSL: Advanced Transformationxsl/advanced_stylesheet.phpxsl/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; if ($GLOBALS['reader']->name == 'item') return $GLOBALS['reader']->expand(); return NULL;}

XSL: Advanced TransformationXSL: Advanced Transformationxsl/advanced_stylesheet.phpxsl/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 */

XSL: Advanced TransformationXSL: Advanced Transformationxsl/advanced_stylesheet.xslxsl/advanced_stylesheet.xsl

<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" 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> </xsl:template>

XSL: Advanced TransformationXSL: Advanced Transformationxsl/advanced_stylesheet.xslxsl/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:template>

</xsl:stylesheet>

XSL: Advanced TransformationXSL: Advanced TransformationResults viewed through a browserResults viewed through a browser

xsl/advanced_stylesheet.htmlxsl/advanced_stylesheet.html

Title: Re: Spreadsheet Writer

URL: http://news.php.net/php.general/241446Published: Thu, 07 Sep 2006 13:52:09 –0400

Title: Re: Spreadsheet Writer

URL: http://news.php.net/php.general/241447Published: Thu, 07 Sep 2006 13:52:09 -0400

Title: Re: Spreadsheet Writer

URL: http://news.php.net/php.general/241448Published: Thu, 07 Sep 2006 13:52:09 -0400

Questions?Questions?

http://www.cdatazone.org/talks/quebec_2007/workshop.zip

rrichards@ctindustries.net