1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\Xml\Element; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\Xml\Reader; 6*a1a3b679SAndreas Boehleruse Sabre\Xml\Writer; 7*a1a3b679SAndreas Boehleruse Sabre\Xml\Element; 8*a1a3b679SAndreas Boehler 9*a1a3b679SAndreas Boehler/** 10*a1a3b679SAndreas Boehler * The XmlFragment element allows you to extract a portion of your xml tree, 11*a1a3b679SAndreas Boehler * and get a well-formed xml string. 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * This goes a bit beyond `innerXml` and friends, as we'll also match all the 14*a1a3b679SAndreas Boehler * correct namespaces. 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * Please note that the XML fragment: 17*a1a3b679SAndreas Boehler * 18*a1a3b679SAndreas Boehler * 1. Will not have an <?xml declaration. 19*a1a3b679SAndreas Boehler * 2. Or a DTD 20*a1a3b679SAndreas Boehler * 3. It will have all the relevant xmlns attributes. 21*a1a3b679SAndreas Boehler * 4. It may not have a root element. 22*a1a3b679SAndreas Boehler */ 23*a1a3b679SAndreas Boehlerclass XmlFragment implements Element { 24*a1a3b679SAndreas Boehler 25*a1a3b679SAndreas Boehler protected $xml; 26*a1a3b679SAndreas Boehler 27*a1a3b679SAndreas Boehler function __construct($xml) { 28*a1a3b679SAndreas Boehler 29*a1a3b679SAndreas Boehler $this->xml = $xml; 30*a1a3b679SAndreas Boehler 31*a1a3b679SAndreas Boehler } 32*a1a3b679SAndreas Boehler 33*a1a3b679SAndreas Boehler function getXml() { 34*a1a3b679SAndreas Boehler 35*a1a3b679SAndreas Boehler return $this->xml; 36*a1a3b679SAndreas Boehler 37*a1a3b679SAndreas Boehler } 38*a1a3b679SAndreas Boehler 39*a1a3b679SAndreas Boehler /** 40*a1a3b679SAndreas Boehler * The xmlSerialize metod is called during xml writing. 41*a1a3b679SAndreas Boehler * 42*a1a3b679SAndreas Boehler * Use the $writer argument to write its own xml serialization. 43*a1a3b679SAndreas Boehler * 44*a1a3b679SAndreas Boehler * An important note: do _not_ create a parent element. Any element 45*a1a3b679SAndreas Boehler * implementing XmlSerializble should only ever write what's considered 46*a1a3b679SAndreas Boehler * its 'inner xml'. 47*a1a3b679SAndreas Boehler * 48*a1a3b679SAndreas Boehler * The parent of the current element is responsible for writing a 49*a1a3b679SAndreas Boehler * containing element. 50*a1a3b679SAndreas Boehler * 51*a1a3b679SAndreas Boehler * This allows serializers to be re-used for different element names. 52*a1a3b679SAndreas Boehler * 53*a1a3b679SAndreas Boehler * If you are opening new elements, you must also close them again. 54*a1a3b679SAndreas Boehler * 55*a1a3b679SAndreas Boehler * @param Writer $writer 56*a1a3b679SAndreas Boehler * @return void 57*a1a3b679SAndreas Boehler */ 58*a1a3b679SAndreas Boehler function xmlSerialize(Writer $writer) { 59*a1a3b679SAndreas Boehler 60*a1a3b679SAndreas Boehler $reader = new Reader(); 61*a1a3b679SAndreas Boehler 62*a1a3b679SAndreas Boehler // Wrapping the xml in a container, so root-less values can still be 63*a1a3b679SAndreas Boehler // parsed. 64*a1a3b679SAndreas Boehler $xml = <<<XML 65*a1a3b679SAndreas Boehler<?xml version="1.0"?> 66*a1a3b679SAndreas Boehler<xml-fragment xmlns="http://sabre.io/ns">{$this->getXml()}</xml-fragment> 67*a1a3b679SAndreas BoehlerXML; 68*a1a3b679SAndreas Boehler 69*a1a3b679SAndreas Boehler $reader->xml($xml); 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler $elementNamespace = null; 72*a1a3b679SAndreas Boehler 73*a1a3b679SAndreas Boehler while ($reader->read()) { 74*a1a3b679SAndreas Boehler 75*a1a3b679SAndreas Boehler if ($reader->depth < 1) { 76*a1a3b679SAndreas Boehler // Skipping the root node. 77*a1a3b679SAndreas Boehler continue; 78*a1a3b679SAndreas Boehler } 79*a1a3b679SAndreas Boehler 80*a1a3b679SAndreas Boehler switch ($reader->nodeType) { 81*a1a3b679SAndreas Boehler 82*a1a3b679SAndreas Boehler case Reader::ELEMENT : 83*a1a3b679SAndreas Boehler $writer->startElement( 84*a1a3b679SAndreas Boehler $reader->getClark() 85*a1a3b679SAndreas Boehler ); 86*a1a3b679SAndreas Boehler $empty = $reader->isEmptyElement; 87*a1a3b679SAndreas Boehler while ($reader->moveToNextAttribute()) { 88*a1a3b679SAndreas Boehler switch ($reader->namespaceURI) { 89*a1a3b679SAndreas Boehler case '' : 90*a1a3b679SAndreas Boehler $writer->writeAttribute($reader->localName, $reader->value); 91*a1a3b679SAndreas Boehler break; 92*a1a3b679SAndreas Boehler case 'http://www.w3.org/2000/xmlns/' : 93*a1a3b679SAndreas Boehler // Skip namespace declarations 94*a1a3b679SAndreas Boehler break; 95*a1a3b679SAndreas Boehler default : 96*a1a3b679SAndreas Boehler $writer->writeAttribute($reader->getClark(), $reader->value); 97*a1a3b679SAndreas Boehler break; 98*a1a3b679SAndreas Boehler } 99*a1a3b679SAndreas Boehler } 100*a1a3b679SAndreas Boehler if ($empty) { 101*a1a3b679SAndreas Boehler $writer->endElement(); 102*a1a3b679SAndreas Boehler } 103*a1a3b679SAndreas Boehler break; 104*a1a3b679SAndreas Boehler case Reader::CDATA : 105*a1a3b679SAndreas Boehler case Reader::TEXT : 106*a1a3b679SAndreas Boehler $writer->text( 107*a1a3b679SAndreas Boehler $reader->value 108*a1a3b679SAndreas Boehler ); 109*a1a3b679SAndreas Boehler break; 110*a1a3b679SAndreas Boehler case Reader::END_ELEMENT : 111*a1a3b679SAndreas Boehler $writer->endElement(); 112*a1a3b679SAndreas Boehler break; 113*a1a3b679SAndreas Boehler 114*a1a3b679SAndreas Boehler } 115*a1a3b679SAndreas Boehler 116*a1a3b679SAndreas Boehler } 117*a1a3b679SAndreas Boehler 118*a1a3b679SAndreas Boehler } 119*a1a3b679SAndreas Boehler 120*a1a3b679SAndreas Boehler /** 121*a1a3b679SAndreas Boehler * The deserialize method is called during xml parsing. 122*a1a3b679SAndreas Boehler * 123*a1a3b679SAndreas Boehler * This method is called statictly, this is because in theory this method 124*a1a3b679SAndreas Boehler * may be used as a type of constructor, or factory method. 125*a1a3b679SAndreas Boehler * 126*a1a3b679SAndreas Boehler * Often you want to return an instance of the current class, but you are 127*a1a3b679SAndreas Boehler * free to return other data as well. 128*a1a3b679SAndreas Boehler * 129*a1a3b679SAndreas Boehler * You are responsible for advancing the reader to the next element. Not 130*a1a3b679SAndreas Boehler * doing anything will result in a never-ending loop. 131*a1a3b679SAndreas Boehler * 132*a1a3b679SAndreas Boehler * If you just want to skip parsing for this element altogether, you can 133*a1a3b679SAndreas Boehler * just call $reader->next(); 134*a1a3b679SAndreas Boehler * 135*a1a3b679SAndreas Boehler * $reader->parseInnerTree() will parse the entire sub-tree, and advance to 136*a1a3b679SAndreas Boehler * the next element. 137*a1a3b679SAndreas Boehler * 138*a1a3b679SAndreas Boehler * @param Reader $reader 139*a1a3b679SAndreas Boehler * @return mixed 140*a1a3b679SAndreas Boehler */ 141*a1a3b679SAndreas Boehler static function xmlDeserialize(Reader $reader) { 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler $result = new self($reader->readInnerXml()); 144*a1a3b679SAndreas Boehler $reader->next(); 145*a1a3b679SAndreas Boehler return $result; 146*a1a3b679SAndreas Boehler 147*a1a3b679SAndreas Boehler } 148*a1a3b679SAndreas Boehler 149*a1a3b679SAndreas Boehler} 150