Overview

Packages

  • awl
    • AuthPlugin
    • AwlDatabase
    • Browser
    • classEditor
    • DataEntry
    • DataUpdate
    • EMail
    • iCalendar
    • MenuSet
    • PgQuery
    • Session
    • Translation
    • User
    • Utilities
    • Validation
    • vCalendar
    • vComponent
    • XMLDocument
    • XMLElement
  • None

Classes

  • AuthPlugin
  • AwlCache
  • AwlDatabase
  • AwlDBDialect
  • AwlQuery
  • AwlUpgrader
  • Browser
  • BrowserColumn
  • DBRecord
  • Editor
  • EditorField
  • EMail
  • EntryField
  • EntryForm
  • iCalComponent
  • iCalendar
  • iCalProp
  • MenuOption
  • MenuSet
  • Multipart
  • PgQuery
  • Session
  • SinglePart
  • User
  • Validation
  • vCalendar
  • vComponent
  • vObject
  • vProperty
  • XMLDocument
  • XMLElement

Functions

  • _awl_connect_configured_database
  • _CompareMenuSequence
  • auth_external
  • auth_other_awl
  • awl_replace_sql_args
  • awl_set_locale
  • awl_version
  • BuildXMLTree
  • check_by_regex
  • check_temporary_passwords
  • clean_string
  • connect_configured_database
  • dbg_error_log
  • dbg_log_array
  • define_byte_mappings
  • deprecated
  • duration
  • fatal
  • force_utf8
  • get_fields
  • getCacheInstance
  • gzdecode
  • i18n
  • init_gettext
  • olson_from_tzstring
  • param_to_global
  • qpg
  • quoted_printable_encode
  • replace_uri_params
  • session_salted_md5
  • session_salted_sha1
  • session_simple_md5
  • session_validate_password
  • sql_from_object
  • sql_from_post
  • trace_bug
  • translate
  • uuid
  • Overview
  • Package
  • Class
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 
<?php
/**
* Handling of namespacing for XML documents
*
* @package awl
* @subpackage XMLDocument
* @author Andrew McMillan <andrew@morphoss.com>
* @copyright Morphoss Ltd - http://www.morphoss.com/
* @license   http://www.gnu.org/licenses/lgpl-3.0.txt  GNU LGPL version 3 or later
*
*/

require_once("XMLElement.php");

/**
* A class for XML Documents which will contain namespaced XML elements
*
* @package   awl
*/
class XMLDocument {

  /**#@+
  * @access private
  */
  /**
  * holds the namespaces which this document has been configured for.
  * @var namespaces
  */
  private $namespaces;

  /**
  * holds the prefixes which are shorthand for the namespaces.
  * @var prefixes
  */
  private $prefixes;

  /**
  * Holds the root document for the tree
  * @var root
  */
  private $root;

  /**
  * Simple XMLDocument constructor
  *
  * @param array $namespaces An array of 'namespace' => 'prefix' pairs, where the prefix is used as a short form for the namespace.
  */
  function __construct( $namespaces = null ) {
    $this->namespaces = array();
    $this->prefixes = array();
    if ( $namespaces != null ) {
      foreach( $namespaces AS $ns => $prefix ) {
        $this->namespaces[$ns] = $prefix;
        $this->prefixes[$prefix] = $prefix;
      }
    }
    $this->next_prefix = 0;
  }

  /**
  * Add a new namespace to the document, optionally specifying it's short prefix
  *
  * @param string $namespace The full namespace name to be added
  * @param string $prefix An optional short form for the namespace.
  */
  function AddNamespace( $namespace, $prefix = null ) {
    if ( !isset($this->namespaces[$namespace]) ) {
      if ( isset($prefix) && ($prefix == "" || isset($this->prefixes[$prefix])) ) $prefix = null;
      if ( $prefix == null ) {
        //  Try and build a prefix based on the first alphabetic character of the last element of the namespace
        if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) {
          $alpha = preg_replace( '/[^a-z]/i', '', $matches[2] );
          $prefix = strtoupper(substr($alpha,0,1));
        }
        else {
          $prefix = 'X';
        }
        $i = "";
        if ( isset($this->prefixes[$prefix]) ) {
          for ( $i=1; $i<10 && isset($this->prefixes["$prefix$i"]); $i++ ) {
          }
        }
        if ( isset($this->prefixes["$prefix$i"]) ) {
          dbg_error_log("ERROR", "Cannot find a free prefix for this namespace");
          exit;
        }
        $prefix = "$prefix$i";
        dbg_error_log("XMLDocument", "auto-assigning prefix of '%s' for ns of '%s'", $prefix, $namespace );
      }
      else if ( $prefix == "" || isset($this->prefixes[$prefix]) ) {
        dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces");
        exit;
      }

      $this->prefixes[$prefix] = $prefix;
      $this->namespaces[$namespace] = $prefix;
    }
    else {
      if ( isset($this->namespaces[$namespace]) && $this->namespaces[$namespace] != $prefix ) {
        dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes");
        exit;
      }
      $this->prefixes[$prefix] = $prefix;
      $this->namespaces[$namespace] = $prefix;
    }
  }

  /**
   * Return the default namespace for this document
   */
  function DefaultNamespace() {
    foreach( $this->namespaces AS $k => $v ) {
      if ( $v == '' ) {
        return $k;
      }
    }
    return '';
  }

  /**
  * Return a tag with namespace stripped and replaced with a short form, and the ns added to the document.
  *
  */
  function GetXmlNsArray() {

    $ns = array();
    foreach( $this->namespaces AS $n => $p ) {
      if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n;
    }

    return $ns;
  }


  /**
  * Return a tag with namespace stripped and replaced with a short form, and the ns added to the document.
  *
  * @param string $in_tag The tag we want a namespace prefix on.
  * @param string $namespace The namespace we want it in (which will be parsed from $in_tag if not present
  * @param string $prefix The prefix we would like to use.  Leave it out and one will be assigned.
  *
  * @return string The tag with a namespace prefix consistent with previous tags in this namespace.
  */
  function Tag( $in_tag, $namespace=null, $prefix=null ) {

    if ( $namespace == null ) {
      // Attempt to split out from namespace:tag
      if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
        $namespace = $matches[1];
        $tag = $matches[2];
      }
      else {
        // There is nothing we can do here
        return $in_tag;
      }
    }
    else {
      $tag = $in_tag;
    }

    if ( !isset($this->namespaces[$namespace]) ) {
      $this->AddNamespace( $namespace, $prefix );
    }
    $prefix = $this->namespaces[$namespace];

    return $prefix . ($prefix == "" ? "" : ":") . $tag;
  }

  static public $ns_dav = 'DAV:';
  static public $ns_caldav = 'urn:ietf:params:xml:ns:caldav';
  static public $ns_carddav = 'urn:ietf:params:xml:ns:carddav';
  static public $ns_calendarserver = 'http://calendarserver.org/ns/';
  
  /**
  * Special helper for namespaced tags.
  *
  * @param object $element The tag are adding a new namespaced element to
  * @param string $tag the tag name, possibly prefixed with the namespace
  * @param mixed  $content The content of the tag
  * @param array  $attributes An array of key/value pairs of attributes.
  * @param string $namespace The namespace for the tag
  *
  */
  function NSElement( &$element, $in_tag, $content=false, $attributes=false, $namespace=null ) {
    if ( $namespace == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
      $namespace = $matches[1];
      if ( preg_match('{^[A-Z][A-Z0-9]*$}', $namespace ) ) {
        throw new Exception("Dodgy looking namespace from '".$in_tag."'!");
      }
      $tag = $matches[2];
    }
    else {
      $tag = $in_tag;
      if ( isset($namespace) ) {
        $tag = str_replace($namespace.':', '', $tag);
      }
    }

    if ( isset($namespace) && !isset($this->namespaces[$namespace]) ) $this->AddNamespace( $namespace );
    return $element->NewElement( $tag, $content, $attributes, $namespace );
  }


  /**
  * Special helper for tags in the DAV: namespace.
  *
  * @param object $element The tag are adding a new namespaced element to
  * @param string $tag the tag name
  * @param mixed  $content The content of the tag
  * @param array  $attributes An array of key/value pairs of attributes.
  */
  function DAVElement( &$element, $tag, $content=false, $attributes=false ) {
    if ( !isset($this->namespaces[self::$ns_dav]) ) $this->AddNamespace( self::$ns_dav, '' );
    return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_dav );
  }

  /**
  * Special helper for tags in the urn:ietf:params:xml:ns:caldav namespace.
  *
  * @param object $element The tag are adding a new namespaced element to
  * @param string $tag the tag name
  * @param mixed  $content The content of the tag
  * @param array  $attributes An array of key/value pairs of attributes.
  */
  function CalDAVElement( &$element, $tag, $content=false, $attributes=false ) {
    if ( !isset($this->namespaces[self::$ns_caldav]) ) $this->AddNamespace( self::$ns_caldav, 'C' );
    return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_caldav );
  }


  /**
  * Special helper for tags in the urn:ietf:params:xml:ns:carddav namespace.
  *
  * @param object $element The tag are adding a new namespaced element to
  * @param string $tag the tag name
  * @param mixed  $content The content of the tag
  * @param array  $attributes An array of key/value pairs of attributes.
  */
  function CardDAVElement( &$element, $tag, $content=false, $attributes=false ) {
    if ( !isset($this->namespaces[self::$ns_carddav]) ) $this->AddNamespace( self::$ns_carddav, 'VC' );
    return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_carddav );
  }


  /**
  * Special helper for tags in the urn:ietf:params:xml:ns:caldav namespace.
  *
  * @param object $element The tag are adding a new namespaced element to
  * @param string $tag the tag name
  * @param mixed  $content The content of the tag
  * @param array  $attributes An array of key/value pairs of attributes.
  */
  function CalendarserverElement( &$element, $tag, $content=false, $attributes=false ) {
    if ( !isset($this->namespaces[self::$ns_calendarserver]) ) $this->AddNamespace( self::$ns_calendarserver, 'A' );
    return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_calendarserver );
  }


  /**
  * @param string $in_tag The tag name of the new element, possibly namespaced
  * @param mixed $content Either a string of content, or an array of sub-elements
  * @param array $attributes An array of attribute name/value pairs
  * @param array $xmlns An XML namespace specifier
  */
  function NewXMLElement( $in_tag, $content=false, $attributes=false, $xmlns=null ) {
    if ( $xmlns == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
      $xmlns = $matches[1];
      $tagname = $matches[2];
    }
    else {
      $tagname = $in_tag;
    }

    if ( isset($xmlns) && !isset($this->namespaces[$xmlns]) ) $this->AddNamespace( $xmlns );
    return new XMLElement($tagname, $content, $attributes, $xmlns );
  }

  /**
  * Render the document tree into (nicely formatted) XML
  *
  * @param mixed $root A root XMLElement or a tagname to create one with the remaining parameters.
  * @param mixed $content Either a string of content, or an array of sub-elements
  * @param array $attributes An array of attribute name/value pairs
  * @param array $xmlns An XML namespace specifier
  *
  * @return A rendered namespaced XML document.
  */
  function Render( $root, $content=false, $attributes=false, $xmlns=null ) {
    if ( is_object($root) ) {
      /** They handed us a pre-existing object.  We'll just use it... */
      $this->root = $root;
    }
    else {
      /** We got a tag name, so we need to create the root element */
      $this->root = $this->NewXMLElement( $root, $content, $attributes, $xmlns );
    }

    /**
    * Add our namespace attributes here.
    */
    foreach( $this->namespaces AS $n => $p ) {
      $this->root->SetAttribute( 'xmlns'.($p == '' ? '' : ':') . $p, $n);
    }

    /** And render... */
    return $this->root->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
  }

  /**
  * Return a DAV::href XML element, or an array of them
  * @param mixed $url The URL (or array of URLs) to be wrapped in DAV::href tags
  *
  * @return XMLElement The newly created XMLElement object.
  */
  function href($url) {
    if ( is_array($url) ) {
      $set = array();
      foreach( $url AS $href ) {
        $set[] = $this->href( $href );
      }
      return $set;
    }
    if ( preg_match('[@+ ]',$url) ) {
      trace_bug('URL "%s" was not encoded before call to XMLDocument::href()', $url );
      $url = str_replace( '%2F', '/', rawurlencode($url));
    }
    return $this->NewXMLElement('href', $url, false, 'DAV:');
  }

}


API documentation generated by ApiGen