home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / XML / Util.php < prev    next >
Encoding:
PHP Script  |  2005-07-07  |  26.7 KB  |  743 lines

  1. <?PHP
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stephan Schmidt <schst@php-tools.net>                       |
  17. // +----------------------------------------------------------------------+
  18. //
  19. //    $Id: Util.php,v 1.24 2004/12/23 13:21:59 schst Exp $
  20.  
  21. /**
  22.  * error code for invalid chars in XML name
  23.  */
  24. define("XML_UTIL_ERROR_INVALID_CHARS", 51);
  25.  
  26. /**
  27.  * error code for invalid chars in XML name
  28.  */
  29. define("XML_UTIL_ERROR_INVALID_START", 52);
  30.  
  31. /**
  32.  * error code for non-scalar tag content
  33.  */
  34. define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
  35.     
  36. /**
  37.  * error code for missing tag name
  38.  */
  39. define("XML_UTIL_ERROR_NO_TAG_NAME", 61);
  40.     
  41. /**
  42.  * replace XML entities
  43.  */
  44. define("XML_UTIL_REPLACE_ENTITIES", 1);
  45.  
  46. /**
  47.  * embedd content in a CData Section
  48.  */
  49. define("XML_UTIL_CDATA_SECTION", 5);
  50.  
  51. /**
  52.  * do not replace entitites
  53.  */
  54. define("XML_UTIL_ENTITIES_NONE", 0);
  55.  
  56. /**
  57.  * replace all XML entitites
  58.  * This setting will replace <, >, ", ' and &
  59.  */
  60. define("XML_UTIL_ENTITIES_XML", 1);
  61.  
  62. /**
  63.  * replace only required XML entitites
  64.  * This setting will replace <, " and &
  65.  */
  66. define("XML_UTIL_ENTITIES_XML_REQUIRED", 2);
  67.  
  68. /**
  69.  * replace HTML entitites
  70.  * @link    http://www.php.net/htmlentities
  71.  */
  72. define("XML_UTIL_ENTITIES_HTML", 3);
  73.  
  74. /**
  75.  * Collapse all empty tags.
  76.  */
  77. define("XML_UTIL_COLLAPSE_ALL", 1);
  78.  
  79. /**
  80.  * Collapse only empty XHTML tags that have no end tag.
  81.  */
  82. define("XML_UTIL_COLLAPSE_XHTML_ONLY", 2);
  83.  
  84. /**
  85.  * utility class for working with XML documents
  86.  *
  87.  * @category XML
  88.  * @package  XML_Util
  89.  * @version  1.1.0
  90.  * @author   Stephan Schmidt <schst@php.net>
  91.  */
  92. class XML_Util {
  93.  
  94.    /**
  95.     * return API version
  96.     *
  97.     * @access   public
  98.     * @static
  99.     * @return   string  $version API version
  100.     */
  101.     function apiVersion()
  102.     {
  103.         return '1.1';
  104.     }
  105.  
  106.    /**
  107.     * replace XML entities
  108.     *
  109.     * With the optional second parameter, you may select, which
  110.     * entities should be replaced.
  111.     *
  112.     * <code>
  113.     * require_once 'XML/Util.php';
  114.     * 
  115.     * // replace XML entites:
  116.     * $string = XML_Util::replaceEntities("This string contains < & >.");
  117.     * </code>
  118.     *
  119.     * @access   public
  120.     * @static
  121.     * @param    string  string where XML special chars should be replaced
  122.     * @param    integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  123.     * @return   string  string with replaced chars
  124.     * @see      reverseEntities()
  125.     */
  126.     function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
  127.     {
  128.         switch ($replaceEntities) {
  129.             case XML_UTIL_ENTITIES_XML:
  130.                 return strtr($string,array(
  131.                                           '&'  => '&',
  132.                                           '>'  => '>',
  133.                                           '<'  => '<',
  134.                                           '"'  => '"',
  135.                                           '\'' => ''' ));
  136.                 break;
  137.             case XML_UTIL_ENTITIES_XML_REQUIRED:
  138.                 return strtr($string,array(
  139.                                           '&'  => '&',
  140.                                           '<'  => '<',
  141.                                           '"'  => '"' ));
  142.                 break;
  143.             case XML_UTIL_ENTITIES_HTML:
  144.                 return htmlentities($string);
  145.                 break;
  146.         }
  147.         return $string;
  148.     }
  149.  
  150.    /**
  151.     * reverse XML entities
  152.     *
  153.     * With the optional second parameter, you may select, which
  154.     * entities should be reversed.
  155.     *
  156.     * <code>
  157.     * require_once 'XML/Util.php';
  158.     * 
  159.     * // reverse XML entites:
  160.     * $string = XML_Util::reverseEntities("This string contains < & >.");
  161.     * </code>
  162.     *
  163.     * @access   public
  164.     * @static
  165.     * @param    string  string where XML special chars should be replaced
  166.     * @param    integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  167.     * @return   string  string with replaced chars
  168.     * @see      replaceEntities()
  169.     */
  170.     function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
  171.     {
  172.         switch ($replaceEntities) {
  173.             case XML_UTIL_ENTITIES_XML:
  174.                 return strtr($string,array(
  175.                                           '&'  => '&',
  176.                                           '>'   => '>',
  177.                                           '<'   => '<',
  178.                                           '"' => '"',
  179.                                           ''' => '\'' ));
  180.                 break;
  181.             case XML_UTIL_ENTITIES_XML_REQUIRED:
  182.                 return strtr($string,array(
  183.                                           '&'  => '&',
  184.                                           '<'   => '<',
  185.                                           '"' => '"' ));
  186.                 break;
  187.             case XML_UTIL_ENTITIES_HTML:
  188.                 $arr = array_flip(get_html_translation_table(HTML_ENTITIES));
  189.                 return strtr($string, $arr);
  190.                 break;
  191.         }
  192.         return $string;
  193.     }
  194.  
  195.    /**
  196.     * build an xml declaration
  197.     *
  198.     * <code>
  199.     * require_once 'XML/Util.php';
  200.     * 
  201.     * // get an XML declaration:
  202.     * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
  203.     * </code>
  204.     *
  205.     * @access   public
  206.     * @static
  207.     * @param    string  $version     xml version
  208.     * @param    string  $encoding    character encoding
  209.     * @param    boolean $standAlone  document is standalone (or not)
  210.     * @return   string  $decl xml declaration
  211.     * @uses     XML_Util::attributesToString() to serialize the attributes of the XML declaration
  212.     */
  213.     function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
  214.     {
  215.         $attributes = array(
  216.                             "version" => $version,
  217.                            );
  218.         // add encoding
  219.         if ($encoding !== null) {
  220.             $attributes["encoding"] = $encoding;
  221.         }
  222.         // add standalone, if specified
  223.         if ($standalone !== null) {
  224.             $attributes["standalone"] = $standalone ? "yes" : "no";
  225.         }
  226.         
  227.         return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
  228.     }
  229.  
  230.    /**
  231.     * build a document type declaration
  232.     *
  233.     * <code>
  234.     * require_once 'XML/Util.php';
  235.     * 
  236.     * // get a doctype declaration:
  237.     * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
  238.     * </code>
  239.     *
  240.     * @access   public
  241.     * @static
  242.     * @param    string  $root         name of the root tag
  243.     * @param    string  $uri          uri of the doctype definition (or array with uri and public id)
  244.     * @param    string  $internalDtd  internal dtd entries   
  245.     * @return   string  $decl         doctype declaration
  246.     * @since    0.2
  247.     */
  248.     function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
  249.     {
  250.         if (is_array($uri)) {
  251.             $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
  252.         } elseif (!empty($uri)) {
  253.             $ref = sprintf( ' SYSTEM "%s"', $uri );
  254.         } else {
  255.             $ref = "";
  256.         }
  257.  
  258.         if (empty($internalDtd)) {
  259.             return sprintf("<!DOCTYPE %s%s>", $root, $ref);
  260.         } else {
  261.             return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  262.         }
  263.     }
  264.  
  265.    /**
  266.     * create string representation of an attribute list
  267.     *
  268.     * <code>
  269.     * require_once 'XML/Util.php';
  270.     * 
  271.     * // build an attribute string
  272.     * $att = array(
  273.     *              "foo"   =>  "bar",
  274.     *              "argh"  =>  "tomato"
  275.     *            );
  276.     *
  277.     * $attList = XML_Util::attributesToString($att);    
  278.     * </code>
  279.     *
  280.     * @access   public
  281.     * @static
  282.     * @param    array         $attributes        attribute array
  283.     * @param    boolean|array $sort              sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
  284.     * @param    boolean       $multiline         use linebreaks, if more than one attribute is given
  285.     * @param    string        $indent            string used for indentation of multiline attributes
  286.     * @param    string        $linebreak         string used for linebreaks of multiline attributes
  287.     * @param    integer       $entities          setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  288.     * @return   string                           string representation of the attributes
  289.     * @uses     XML_Util::replaceEntities() to replace XML entities in attribute values
  290.     * @todo     allow sort also to be an options array
  291.     */
  292.     function attributesToString($attributes, $sort = true, $multiline = false, $indent = '    ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
  293.     {
  294.         /**
  295.          * second parameter may be an array
  296.          */
  297.         if (is_array($sort)) {
  298.             if (isset($sort['multiline'])) {
  299.                 $multiline = $sort['multiline'];
  300.             }
  301.             if (isset($sort['indent'])) {
  302.                 $indent = $sort['indent'];
  303.             }
  304.             if (isset($sort['linebreak'])) {
  305.                 $multiline = $sort['linebreak'];
  306.             }
  307.             if (isset($sort['entities'])) {
  308.                 $entities = $sort['entities'];
  309.             }
  310.             if (isset($sort['sort'])) {
  311.                 $sort = $sort['sort'];
  312.             } else {
  313.                 $sort = true;
  314.             }
  315.         }
  316.         $string = '';
  317.         if (is_array($attributes) && !empty($attributes)) {
  318.             if ($sort) {
  319.                 ksort($attributes);
  320.             }
  321.             if( !$multiline || count($attributes) == 1) {
  322.                 foreach ($attributes as $key => $value) {
  323.                     if ($entities != XML_UTIL_ENTITIES_NONE) {
  324.                         if ($entities === XML_UTIL_CDATA_SECTION) {
  325.                             $entities = XML_UTIL_ENTITIES_XML;
  326.                         }
  327.                         $value = XML_Util::replaceEntities($value, $entities);
  328.                     }
  329.                     $string .= ' '.$key.'="'.$value.'"';
  330.                 }
  331.             } else {
  332.                 $first = true;
  333.                 foreach ($attributes as $key => $value) {
  334.                     if ($entities != XML_UTIL_ENTITIES_NONE) {
  335.                         $value = XML_Util::replaceEntities($value, $entities);
  336.                     }
  337.                     if ($first) {
  338.                         $string .= " ".$key.'="'.$value.'"';
  339.                         $first = false;
  340.                     } else {
  341.                         $string .= $linebreak.$indent.$key.'="'.$value.'"';
  342.                     }
  343.                 }
  344.             }
  345.         }
  346.         return $string;
  347.     }
  348.  
  349.    /**
  350.     * Collapses empty tags.
  351.     *
  352.     * @access   public
  353.     * @static
  354.     * @param    string  $xml  XML
  355.     * @param    integer $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
  356.     * @return   string  $xml  XML
  357.     */
  358.     function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) {
  359.         if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) {
  360.             return preg_replace(
  361.               '/<(area|base|br|col|hr|img|input|link|meta|param)([^>]*)><\/\\1>/s',
  362.               '<\\1\\2 />',
  363.               $xml
  364.             );
  365.         } else {
  366.             return preg_replace(
  367.               '/<(\w+)([^>]*)><\/\\1>/s',
  368.               '<\\1\\2 />',
  369.               $xml
  370.             );
  371.         }
  372.     }
  373.  
  374.    /**
  375.     * create a tag
  376.     *
  377.     * This method will call XML_Util::createTagFromArray(), which
  378.     * is more flexible.
  379.     *
  380.     * <code>
  381.     * require_once 'XML/Util.php';
  382.     * 
  383.     * // create an XML tag:
  384.     * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
  385.     * </code>
  386.     *
  387.     * @access   public
  388.     * @static
  389.     * @param    string  $qname             qualified tagname (including namespace)
  390.     * @param    array   $attributes        array containg attributes
  391.     * @param    mixed   $content
  392.     * @param    string  $namespaceUri      URI of the namespace
  393.     * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
  394.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  395.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  396.     * @param    string  $linebreak         string used for linebreaks
  397.     * @return   string  $string            XML tag
  398.     * @see      XML_Util::createTagFromArray()
  399.     * @uses     XML_Util::createTagFromArray() to create the tag
  400.     */
  401.     function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n")
  402.     {
  403.         $tag = array(
  404.                      "qname"      => $qname,
  405.                      "attributes" => $attributes
  406.                     );
  407.  
  408.         // add tag content
  409.         if ($content !== null) {
  410.             $tag["content"] = $content;
  411.         }
  412.         
  413.         // add namespace Uri
  414.         if ($namespaceUri !== null) {
  415.             $tag["namespaceUri"] = $namespaceUri;
  416.         }
  417.  
  418.         return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak);
  419.     }
  420.  
  421.    /**
  422.     * create a tag from an array
  423.     * this method awaits an array in the following format
  424.     * <pre>
  425.     * array(
  426.     *  "qname"        => $qname         // qualified name of the tag
  427.     *  "namespace"    => $namespace     // namespace prefix (optional, if qname is specified or no namespace)
  428.     *  "localpart"    => $localpart,    // local part of the tagname (optional, if qname is specified)
  429.     *  "attributes"   => array(),       // array containing all attributes (optional)
  430.     *  "content"      => $content,      // tag content (optional)
  431.     *  "namespaceUri" => $namespaceUri  // namespaceUri for the given namespace (optional)
  432.     *   )
  433.     * </pre>
  434.     *
  435.     * <code>
  436.     * require_once 'XML/Util.php';
  437.     * 
  438.     * $tag = array(
  439.     *           "qname"        => "foo:bar",
  440.     *           "namespaceUri" => "http://foo.com",
  441.     *           "attributes"   => array( "key" => "value", "argh" => "fruit&vegetable" ),
  442.     *           "content"      => "I'm inside the tag",
  443.     *            );
  444.     * // creating a tag with qualified name and namespaceUri
  445.     * $string = XML_Util::createTagFromArray($tag);
  446.     * </code>
  447.     *
  448.     * @access   public
  449.     * @static
  450.     * @param    array   $tag               tag definition
  451.     * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
  452.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  453.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  454.     * @param    string  $linebreak         string used for linebreaks
  455.     * @return   string  $string            XML tag
  456.     * @see      XML_Util::createTag()
  457.     * @uses     XML_Util::attributesToString() to serialize the attributes of the tag
  458.     * @uses     XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
  459.     */
  460.     function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n" )
  461.     {
  462.         if (isset($tag['content']) && !is_scalar($tag['content'])) {
  463.             return XML_Util::raiseError( 'Supplied non-scalar value as tag content', XML_UTIL_ERROR_NON_SCALAR_CONTENT );
  464.         }
  465.  
  466.         if (!isset($tag['qname']) && !isset($tag['localPart'])) {
  467.             return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME );
  468.         }
  469.  
  470.         // if no attributes hav been set, use empty attributes
  471.         if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
  472.             $tag["attributes"] = array();
  473.         }
  474.         
  475.         // qualified name is not given
  476.         if (!isset($tag["qname"])) {
  477.             // check for namespace
  478.             if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  479.                 $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
  480.             } else {
  481.                 $tag["qname"] = $tag["localPart"];
  482.             }
  483.         // namespace URI is set, but no namespace
  484.         } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
  485.             $parts = XML_Util::splitQualifiedName($tag["qname"]);
  486.             $tag["localPart"] = $parts["localPart"];
  487.             if (isset($parts["namespace"])) {
  488.                 $tag["namespace"] = $parts["namespace"];
  489.             }
  490.         }
  491.  
  492.         if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
  493.             // is a namespace given
  494.             if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  495.                 $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
  496.             } else {
  497.                 // define this Uri as the default namespace
  498.                 $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
  499.             }
  500.         }
  501.  
  502.         // check for multiline attributes
  503.         if ($multiline === true) {
  504.             if ($indent === "_auto") {
  505.                 $indent = str_repeat(" ", (strlen($tag["qname"])+2));
  506.             }
  507.         }
  508.         
  509.         // create attribute list
  510.         $attList    =   XML_Util::attributesToString($tag['attributes'], true, $multiline, $indent, $linebreak, $replaceEntities );
  511.         if (!isset($tag['content']) || (string)$tag['content'] == '') {
  512.             $tag    =   sprintf('<%s%s />', $tag['qname'], $attList);
  513.         } else {
  514.             switch ($replaceEntities) {
  515.                 case XML_UTIL_ENTITIES_NONE:
  516.                     break;
  517.                 case XML_UTIL_CDATA_SECTION:
  518.                     $tag['content'] = XML_Util::createCDataSection($tag['content']);
  519.                     break;
  520.                 default:
  521.                     $tag['content'] = XML_Util::replaceEntities($tag['content'], $replaceEntities);
  522.                     break;
  523.             }
  524.             $tag    =   sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'], $tag['qname'] );
  525.         }        
  526.         return  $tag;
  527.     }
  528.  
  529.    /**
  530.     * create a start element
  531.     *
  532.     * <code>
  533.     * require_once 'XML/Util.php';
  534.     * 
  535.     * // create an XML start element:
  536.     * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
  537.     * </code>
  538.     *
  539.     * @access   public
  540.     * @static
  541.     * @param    string  $qname             qualified tagname (including namespace)
  542.     * @param    array   $attributes        array containg attributes
  543.     * @param    string  $namespaceUri      URI of the namespace
  544.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  545.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  546.     * @param    string  $linebreak         string used for linebreaks
  547.     * @return   string  $string            XML start element
  548.     * @see      XML_Util::createEndElement(), XML_Util::createTag()
  549.     */
  550.     function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n")
  551.     {
  552.         // if no attributes hav been set, use empty attributes
  553.         if (!isset($attributes) || !is_array($attributes)) {
  554.             $attributes = array();
  555.         }
  556.         
  557.         if ($namespaceUri != null) {
  558.             $parts = XML_Util::splitQualifiedName($qname);
  559.         }
  560.  
  561.         // check for multiline attributes
  562.         if ($multiline === true) {
  563.             if ($indent === "_auto") {
  564.                 $indent = str_repeat(" ", (strlen($qname)+2));
  565.             }
  566.         }
  567.  
  568.         if ($namespaceUri != null) {
  569.             // is a namespace given
  570.             if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
  571.                 $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
  572.             } else {
  573.                 // define this Uri as the default namespace
  574.                 $attributes["xmlns"] = $namespaceUri;
  575.             }
  576.         }
  577.  
  578.         // create attribute list
  579.         $attList    =   XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak);
  580.         $element    =   sprintf("<%s%s>", $qname, $attList);
  581.         return  $element;
  582.     }
  583.  
  584.    /**
  585.     * create an end element
  586.     *
  587.     * <code>
  588.     * require_once 'XML/Util.php';
  589.     * 
  590.     * // create an XML start element:
  591.     * $tag = XML_Util::createEndElement("myNs:myTag");
  592.     * </code>
  593.     *
  594.     * @access   public
  595.     * @static
  596.     * @param    string  $qname             qualified tagname (including namespace)
  597.     * @return   string  $string            XML end element
  598.     * @see      XML_Util::createStartElement(), XML_Util::createTag()
  599.     */
  600.     function createEndElement($qname)
  601.     {
  602.         $element    =   sprintf("</%s>", $qname);
  603.         return  $element;
  604.     }
  605.     
  606.    /**
  607.     * create an XML comment
  608.     *
  609.     * <code>
  610.     * require_once 'XML/Util.php';
  611.     * 
  612.     * // create an XML start element:
  613.     * $tag = XML_Util::createComment("I am a comment");
  614.     * </code>
  615.     *
  616.     * @access   public
  617.     * @static
  618.     * @param    string  $content           content of the comment
  619.     * @return   string  $comment           XML comment
  620.     */
  621.     function createComment($content)
  622.     {
  623.         $comment    =   sprintf("<!-- %s -->", $content);
  624.         return  $comment;
  625.     }
  626.     
  627.    /**
  628.     * create a CData section
  629.     *
  630.     * <code>
  631.     * require_once 'XML/Util.php';
  632.     * 
  633.     * // create a CData section
  634.     * $tag = XML_Util::createCDataSection("I am content.");
  635.     * </code>
  636.     *
  637.     * @access   public
  638.     * @static
  639.     * @param    string  $data              data of the CData section
  640.     * @return   string  $string            CData section with content
  641.     */
  642.     function createCDataSection($data)
  643.     {
  644.         return  sprintf("<![CDATA[%s]]>", $data);
  645.     }
  646.  
  647.    /**
  648.     * split qualified name and return namespace and local part
  649.     *
  650.     * <code>
  651.     * require_once 'XML/Util.php';
  652.     * 
  653.     * // split qualified tag
  654.     * $parts = XML_Util::splitQualifiedName("xslt:stylesheet");
  655.     * </code>
  656.     * the returned array will contain two elements:
  657.     * <pre>
  658.     * array(
  659.     *       "namespace" => "xslt",
  660.     *       "localPart" => "stylesheet"
  661.     *      );
  662.     * </pre>
  663.     *
  664.     * @access public
  665.     * @static
  666.     * @param  string    $qname      qualified tag name
  667.     * @param  string    $defaultNs  default namespace (optional)
  668.     * @return array     $parts      array containing namespace and local part
  669.     */
  670.     function splitQualifiedName($qname, $defaultNs = null)
  671.     {
  672.         if (strstr($qname, ':')) {
  673.             $tmp = explode(":", $qname);
  674.             return array(
  675.                           "namespace" => $tmp[0],
  676.                           "localPart" => $tmp[1]
  677.                         );
  678.         }
  679.         return array(
  680.                       "namespace" => $defaultNs,
  681.                       "localPart" => $qname
  682.                     );
  683.     }
  684.  
  685.    /**
  686.     * check, whether string is valid XML name
  687.     *
  688.     * <p>XML names are used for tagname, attribute names and various
  689.     * other, lesser known entities.</p>
  690.     * <p>An XML name may only consist of alphanumeric characters,
  691.     * dashes, undescores and periods, and has to start with a letter
  692.     * or an underscore.
  693.     * </p>
  694.     *
  695.     * <code>
  696.     * require_once 'XML/Util.php';
  697.     * 
  698.     * // verify tag name
  699.     * $result = XML_Util::isValidName("invalidTag?");
  700.     * if (XML_Util::isError($result)) {
  701.     *    print "Invalid XML name: " . $result->getMessage();
  702.     * }
  703.     * </code>
  704.     *
  705.     * @access  public
  706.     * @static
  707.     * @param   string  $string string that should be checked
  708.     * @return  mixed   $valid  true, if string is a valid XML name, PEAR error otherwise
  709.     * @todo    support for other charsets
  710.     */
  711.     function isValidName($string)
  712.     {
  713.         // check for invalid chars
  714.         if (!preg_match("/^[[:alnum:]_\-.]$/", $string{0})) {
  715.             return XML_Util::raiseError( "XML names may only start with letter or underscore", XML_UTIL_ERROR_INVALID_START );
  716.         }
  717.         
  718.         // check for invalid chars
  719.         if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $string)) {
  720.             return XML_Util::raiseError( "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores", XML_UTIL_ERROR_INVALID_CHARS );
  721.          }
  722.         // XML name is valid
  723.         return true;
  724.     }
  725.  
  726.    /**
  727.     * replacement for XML_Util::raiseError
  728.     *
  729.     * Avoids the necessity to always require
  730.     * PEAR.php
  731.     *
  732.     * @access   public
  733.     * @param    string      error message
  734.     * @param    integer     error code
  735.     * @return   object PEAR_Error
  736.     */
  737.     function raiseError($msg, $code)
  738.     {
  739.         require_once 'PEAR.php';
  740.         return PEAR::raiseError($msg, $code);
  741.     }
  742. }
  743. ?>