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