Back to index

awl  0.53
XMLDocument.php
Go to the documentation of this file.
00001 <?php
00013 require_once("XMLElement.php");
00014 
00020 class XMLDocument {
00021 
00029   private $namespaces;
00030 
00035   private $prefixes;
00036 
00041   private $root;
00042 
00048   function __construct( $namespaces = null ) {
00049     $this->namespaces = array();
00050     $this->prefixes = array();
00051     if ( $namespaces != null ) {
00052       foreach( $namespaces AS $ns => $prefix ) {
00053         $this->namespaces[$ns] = $prefix;
00054         $this->prefixes[$prefix] = $prefix;
00055       }
00056     }
00057     $this->next_prefix = 0;
00058   }
00059 
00066   function AddNamespace( $namespace, $prefix = null ) {
00067     if ( !isset($this->namespaces[$namespace]) ) {
00068       if ( isset($prefix) && ($prefix == "" || isset($this->prefixes[$prefix])) ) $prefix = null;
00069       if ( $prefix == null ) {
00070         //  Try and build a prefix based on the first alphabetic character of the last element of the namespace
00071         if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) {
00072           $alpha = preg_replace( '/[^a-z]/i', '', $matches[2] );
00073           $prefix = strtoupper(substr($alpha,0,1));
00074         }
00075         else {
00076           $prefix = 'X';
00077         }
00078         $i = "";
00079         if ( isset($this->prefixes[$prefix]) ) {
00080           for ( $i=1; $i<10 && isset($this->prefixes["$prefix$i"]); $i++ ) {
00081           }
00082         }
00083         if ( isset($this->prefixes["$prefix$i"]) ) {
00084           dbg_error_log("ERROR", "Cannot find a free prefix for this namespace");
00085           exit;
00086         }
00087         $prefix = "$prefix$i";
00088         dbg_error_log("XMLDocument", "auto-assigning prefix of '%s' for ns of '%s'", $prefix, $namespace );
00089       }
00090       else if ( $prefix == "" || isset($this->prefixes[$prefix]) ) {
00091         dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces");
00092         exit;
00093       }
00094 
00095       $this->prefixes[$prefix] = $prefix;
00096       $this->namespaces[$namespace] = $prefix;
00097     }
00098     else {
00099       if ( isset($this->namespaces[$namespace]) && $this->namespaces[$namespace] != $prefix ) {
00100         dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes");
00101         exit;
00102       }
00103       $this->prefixes[$prefix] = $prefix;
00104       $this->namespaces[$namespace] = $prefix;
00105     }
00106   }
00107 
00111   function DefaultNamespace() {
00112     foreach( $this->namespaces AS $k => $v ) {
00113       if ( $v == '' ) {
00114         return $k;
00115       }
00116     }
00117     return '';
00118   }
00119 
00124   function GetXmlNsArray() {
00125 
00126     $ns = array();
00127     foreach( $this->namespaces AS $n => $p ) {
00128       if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n;
00129     }
00130 
00131     return $ns;
00132   }
00133 
00134 
00144   function Tag( $in_tag, $namespace=null, $prefix=null ) {
00145 
00146     if ( $namespace == null ) {
00147       // Attempt to split out from namespace:tag
00148       if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
00149         $namespace = $matches[1];
00150         $tag = $matches[2];
00151       }
00152       else {
00153         // There is nothing we can do here
00154         return $in_tag;
00155       }
00156     }
00157     else {
00158       $tag = $in_tag;
00159     }
00160 
00161     if ( !isset($this->namespaces[$namespace]) ) {
00162       $this->AddNamespace( $namespace, $prefix );
00163     }
00164     $prefix = $this->namespaces[$namespace];
00165 
00166     return $prefix . ($prefix == "" ? "" : ":") . $tag;
00167   }
00168 
00169   static public $ns_dav = 'DAV:';
00170   static public $ns_caldav = 'urn:ietf:params:xml:ns:caldav';
00171   static public $ns_carddav = 'urn:ietf:params:xml:ns:carddav';
00172   static public $ns_calendarserver = 'http://calendarserver.org/ns/';
00173   
00184   function NSElement( &$element, $in_tag, $content=false, $attributes=false, $namespace=null ) {
00185     if ( $namespace == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
00186       $namespace = $matches[1];
00187       if ( preg_match('{^[A-Z][A-Z0-9]*$}', $namespace ) ) {
00188         throw new Exception("Dodgy looking namespace from '".$in_tag."'!");
00189       }
00190       $tag = $matches[2];
00191     }
00192     else {
00193       $tag = $in_tag;
00194       if ( isset($namespace) ) {
00195         $tag = str_replace($namespace.':', '', $tag);
00196       }
00197     }
00198 
00199     if ( isset($namespace) && !isset($this->namespaces[$namespace]) ) $this->AddNamespace( $namespace );
00200     return $element->NewElement( $tag, $content, $attributes, $namespace );
00201   }
00202 
00203 
00212   function DAVElement( &$element, $tag, $content=false, $attributes=false ) {
00213     if ( !isset($this->namespaces[self::$ns_dav]) ) $this->AddNamespace( self::$ns_dav, '' );
00214     return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_dav );
00215   }
00216 
00225   function CalDAVElement( &$element, $tag, $content=false, $attributes=false ) {
00226     if ( !isset($this->namespaces[self::$ns_caldav]) ) $this->AddNamespace( self::$ns_caldav, 'C' );
00227     return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_caldav );
00228   }
00229 
00230 
00239   function CardDAVElement( &$element, $tag, $content=false, $attributes=false ) {
00240     if ( !isset($this->namespaces[self::$ns_carddav]) ) $this->AddNamespace( self::$ns_carddav, 'VC' );
00241     return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_carddav );
00242   }
00243 
00244 
00253   function CalendarserverElement( &$element, $tag, $content=false, $attributes=false ) {
00254     if ( !isset($this->namespaces[self::$ns_calendarserver]) ) $this->AddNamespace( self::$ns_calendarserver, 'A' );
00255     return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_calendarserver );
00256   }
00257 
00258 
00265   function NewXMLElement( $in_tag, $content=false, $attributes=false, $xmlns=null ) {
00266     if ( $xmlns == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
00267       $xmlns = $matches[1];
00268       $tagname = $matches[2];
00269     }
00270     else {
00271       $tagname = $in_tag;
00272     }
00273 
00274     if ( isset($xmlns) && !isset($this->namespaces[$xmlns]) ) $this->AddNamespace( $xmlns );
00275     return new XMLElement($tagname, $content, $attributes, $xmlns );
00276   }
00277 
00288   function Render( $root, $content=false, $attributes=false, $xmlns=null ) {
00289     if ( is_object($root) ) {
00291       $this->root = $root;
00292     }
00293     else {
00295       $this->root = $this->NewXMLElement( $root, $content, $attributes, $xmlns );
00296     }
00297 
00301     foreach( $this->namespaces AS $n => $p ) {
00302       $this->root->SetAttribute( 'xmlns'.($p == '' ? '' : ':') . $p, $n);
00303     }
00304 
00306     return $this->root->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
00307   }
00308 
00315   function href($url) {
00316     if ( is_array($url) ) {
00317       $set = array();
00318       foreach( $url AS $href ) {
00319         $set[] = $this->href( $href );
00320       }
00321       return $set;
00322     }
00323     if ( preg_match('[@+ ]',$url) ) {
00324       trace_bug('URL "%s" was not encoded before call to XMLDocument::href()', $url );
00325       $url = str_replace( '%2F', '/', rawurlencode($url));
00326     }
00327     return $this->NewXMLElement('href', $url, false, 'DAV:');
00328   }
00329 
00330 }
00331 
00332