Andrew's Web Libraries (AWL)
XMLElement.php
1 <?php
12 require_once('AWLUtilities.php');
13 
20 class XMLElement {
21  protected $tagname;
22  protected $xmlns;
23  protected $attributes;
24  protected $content;
25  protected $_parent;
26 
35  function __construct( $tagname, $content=false, $attributes=false, $xmlns=null ) {
36  $this->tagname=$tagname;
37  if ( gettype($content) == "object" ) {
38  // Subtree to be parented here
39  $this->content = array(&$content);
40  }
41  else {
42  // Array or text
43  $this->content = $content;
44  }
45  $this->attributes = $attributes;
46  if ( $this->attributes === false ) $this->attributes = array();
47  if ( isset($xmlns) ) {
48  $this->xmlns = $xmlns;
49  }
50  else {
51  if ( preg_match( '{^(.*):([^:]*)$}', $tagname, $matches) ) {
52  $prefix = $matches[1];
53  $tag = $matches[2];
54  if ( isset($this->attributes['xmlns:'.$prefix]) ) {
55  $this->xmlns = $this->attributes['xmlns:'.$prefix];
56  }
57  }
58  else if ( isset($this->attributes['xmlns']) ) {
59  $this->xmlns = $this->attributes['xmlns'];
60  }
61  }
62  }
63 
64 
69  function CountElements( ) {
70  if ( $this->content === false ) return 0;
71  if ( is_array($this->content) ) return count($this->content);
72  if ( $this->content == '' ) return 0;
73  return 1;
74  }
75 
82  function SetAttribute($k,$v) {
83  if ( gettype($this->attributes) != "array" ) $this->attributes = array();
84  $this->attributes[$k] = $v;
85  if ( strtolower($k) == 'xmlns' ) {
86  $this->xmlns = $v;
87  }
88  }
89 
95  function SetContent($v) {
96  $this->content = $v;
97  }
98 
104  function GetTag() {
105  return $this->tagname;
106  }
107 
113  function GetNSTag() {
114  return (empty($this->xmlns) ? '' : $this->xmlns . ':') . $this->tagname;
115  }
116 
122  function GetAttribute( $attr ) {
123  if ( $attr == 'xmlns' ) return $this->xmlns;
124  if ( isset($this->attributes[$attr]) ) return $this->attributes[$attr];
125  return null;
126  }
127 
133  function GetAttributes() {
134  return $this->attributes;
135  }
136 
142  function GetContent() {
143  return $this->content;
144  }
145 
152  function GetElements( $tag=null, $recursive=false ) {
153  $elements = array();
154  if ( gettype($this->content) == "array" ) {
155  foreach( $this->content AS $k => $v ) {
156  if ( empty($tag) || $v->GetNSTag() == $tag ) {
157  $elements[] = $v;
158  }
159  if ( $recursive ) {
160  $elements = $elements + $v->GetElements($tag,true);
161  }
162  }
163  }
164  else if ( empty($tag) || (isset($v->content->tagname) && $v->content->GetNSTag() == $tag) ) {
165  $elements[] = $this->content;
166  }
167  return $elements;
168  }
169 
170 
176  function GetPath( $path ) {
177  $elements = array();
178  // printf( "Querying within '%s' for path '%s'\n", $this->tagname, $path );
179  if ( !preg_match( '#(/)?([^/]+)(/?.*)$#', $path, $matches ) ) return $elements;
180  // printf( "Matches: %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3] );
181  if ( $matches[2] == '*' || $matches[2] == $this->GetNSTag()) {
182  if ( $matches[3] == '' ) {
186  $elements[] = $this;
187  }
188  else if ( gettype($this->content) == "array" ) {
192  foreach( $this->content AS $k => $v ) {
193  $elements = array_merge( $elements, $v->GetPath($matches[3]) );
194  }
195  }
196  }
197 
198  if ( $matches[1] != '/' && gettype($this->content) == "array" ) {
202  foreach( $this->content AS $k => $v ) {
203  $elements = array_merge( $elements, $v->GetPath($path) );
204  }
205  }
206  // printf( "Found %d within '%s' for path '%s'\n", count($elements), $this->tagname, $path );
207  return $elements;
208  }
209 
210 
216  function AddSubTag(&$v) {
217  if ( gettype($this->content) != "array" ) $this->content = array();
218  $this->content[] =& $v;
219  return count($this->content);
220  }
221 
231  function &NewElement( $tagname, $content=false, $attributes=false, $xmlns=null ) {
232  if ( gettype($this->content) != "array" ) $this->content = array();
233  $element = new XMLElement($tagname,$content,$attributes,$xmlns);
234  $this->content[] =& $element;
235  return $element;
236  }
237 
238 
244  function RenderContent($indent=0, $nslist=null, $force_xmlns=false ) {
245  $r = "";
246  if ( is_array($this->content) ) {
250  $r .= "\n";
251  foreach( $this->content AS $k => $v ) {
252  if ( is_object($v) ) {
253  $r .= $v->Render($indent+1, "", $nslist, $force_xmlns);
254  }
255  }
256  $r .= substr(" ",0,$indent);
257  }
258  else {
263  if(strpos($this->content, '<![CDATA[')===0 && strrpos($this->content, ']]>')===strlen($this->content)-3)
264  $r .= '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', substr($this->content, 9, -3)) . ']]>';
265  else if ( defined('ENT_XML1') && defined('ENT_DISALLOWED') )
266  // Newer PHP versions allow specifying ENT_XML1, but default to ENT_HTML401. Go figure. #PHPWTF
267  $r .= htmlspecialchars($this->content, ENT_NOQUOTES | ENT_XML1 | ENT_DISALLOWED );
268  // Need to work out exactly how to do this in PHP.
269  // else if ( preg_match('{^[\t\n\r\x0020-\xD7FF\xE000-\xFFFD\x10000-\x10FFFF]+$}u', utf8ToUnicode($this->content)) )
270  // $r .= '<![CDATA[' . $this->content . ']]>';
271  else
272  // Older PHP versions default to ENT_XML1.
273  $r .= htmlspecialchars($this->content, ENT_NOQUOTES );
274  }
275  return $r;
276  }
277 
278 
284  function Render($indent=0, $xmldef="", $nslist=null, $force_xmlns=false) {
285  $r = ( $xmldef == "" ? "" : $xmldef."\n");
286 
287  $attr = "";
288  $tagname = $this->tagname;
289  $xmlns_done = false;
290  if ( gettype($this->attributes) == "array" ) {
294  foreach( $this->attributes AS $k => $v ) {
295  if ( preg_match('#^xmlns(:?(.+))?$#', $k, $matches ) ) {
296 // if ( $force_xmlns ) printf( "1: %s: %s\n", $this->tagname, $this->xmlns );
297  if ( !isset($nslist) ) $nslist = array();
298  $prefix = (isset($matches[2]) ? $matches[2] : '');
299  if ( isset($nslist[$v]) && $nslist[$v] == $prefix ) continue; // No need to include in list as it's in a wrapping element
300  $nslist[$v] = $prefix;
301  if ( !isset($this->xmlns) ) $this->xmlns = $v;
302  $xmlns_done = true;
303  }
304  $attr .= sprintf( ' %s="%s"', $k, htmlspecialchars($v) );
305  }
306  }
307  if ( isset($this->xmlns) && isset($nslist[$this->xmlns]) && $nslist[$this->xmlns] != '' ) {
308 // if ( $force_xmlns ) printf( "2: %s: %s\n", $this->tagname, $this->xmlns );
309  $tagname = $nslist[$this->xmlns] . ':' . $tagname;
310  if ( $force_xmlns ) $attr .= sprintf( ' xmlns="%s"', $this->xmlns);
311  }
312  else if ( isset($this->xmlns) && !isset($nslist[$this->xmlns]) && gettype($this->attributes) == 'array' && !isset($this->attributes[$this->xmlns]) ) {
313 // if ( $force_xmlns ) printf( "3: %s: %s\n", $this->tagname, $this->xmlns );
314  $attr .= sprintf( ' xmlns="%s"', $this->xmlns);
315  }
316  else if ( $force_xmlns && isset($this->xmlns) && ! $xmlns_done ) {
317 // printf( "4: %s: %s\n", $this->tagname, $this->xmlns );
318  $attr .= sprintf( ' xmlns="%s"', $this->xmlns);
319  }
320 
321  $r .= substr(" ",0,$indent) . '<' . $tagname . $attr;
322 
323  if ( isset($this->content) && ((is_array($this->content) && count($this->content) > 0) || (!is_array($this->content) && strlen($this->content) > 0)) ) {
324  $r .= ">";
325  $r .= $this->RenderContent($indent,$nslist,$force_xmlns);
326  $r .= '</' . $tagname.">\n";
327  }
328  else {
329  $r .= "/>\n";
330  }
331  return $r;
332  }
333 
334 
335  function __tostring() {
336  return $this->Render();
337  }
338 }
339 
340 
349 function BuildXMLTree( $xmltags, &$start_from ) {
350  $content = array();
351 
352  if ( !isset($start_from) ) $start_from = 0;
353 
354  for( $i=0; $i < 50000 && isset($xmltags[$start_from]); $i++) {
355  $tagdata = $xmltags[$start_from++];
356  if ( !isset($tagdata) || !isset($tagdata['tag']) || !isset($tagdata['type']) ) break;
357  if ( $tagdata['type'] == "close" ) break;
358  $xmlns = null;
359  $tag = $tagdata['tag'];
360  if ( preg_match( '{^(.*):([^:]*)$}', $tag, $matches) ) {
361  $xmlns = $matches[1];
362  $tag = $matches[2];
363  }
364  $attributes = ( isset($tagdata['attributes']) ? $tagdata['attributes'] : false );
365  if ( $tagdata['type'] == "open" ) {
366  $subtree = BuildXMLTree( $xmltags, $start_from );
367  $content[] = new XMLElement($tag, $subtree, $attributes, $xmlns );
368  }
369  else if ( $tagdata['type'] == "complete" ) {
370  $value = ( isset($tagdata['value']) ? $tagdata['value'] : false );
371  $content[] = new XMLElement($tag, $value, $attributes, $xmlns );
372  }
373  }
374 
379  if ( count($content) == 1 ) {
380  return $content[0];
381  }
382  return $content;
383 }
384 
SetAttribute($k, $v)
Definition: XMLElement.php:82
& NewElement( $tagname, $content=false, $attributes=false, $xmlns=null)
Definition: XMLElement.php:231
__construct( $tagname, $content=false, $attributes=false, $xmlns=null)
Definition: XMLElement.php:35
GetAttribute( $attr)
Definition: XMLElement.php:122
SetContent($v)
Definition: XMLElement.php:95
Render($indent=0, $xmldef="", $nslist=null, $force_xmlns=false)
Definition: XMLElement.php:284
AddSubTag(&$v)
Definition: XMLElement.php:216
GetElements( $tag=null, $recursive=false)
Definition: XMLElement.php:152
RenderContent($indent=0, $nslist=null, $force_xmlns=false)
Definition: XMLElement.php:244
GetPath( $path)
Definition: XMLElement.php:176