Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: *//*** XML_Util** XML Utilities package** PHP versions 4 and 5** LICENSE:** Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:** * Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.* * Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* * The name of the author may not be used to endorse or promote products* derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.** @category XML* @package XML_Util* @author Stephan Schmidt <schst@php.net>* @copyright 2003-2008 Stephan Schmidt <schst@php.net>* @license http://opensource.org/licenses/bsd-license New BSD License* @version CVS: $Id: Util.php,v 1.38 2008/11/13 00:03:38 ashnazg Exp $* @link http://pear.php.net/package/XML_Util*//*** error code for invalid chars in XML name*/define('XML_UTIL_ERROR_INVALID_CHARS', 51);/*** error code for invalid chars in XML name*/define('XML_UTIL_ERROR_INVALID_START', 52);/*** error code for non-scalar tag content*/define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60);/*** error code for missing tag name*/define('XML_UTIL_ERROR_NO_TAG_NAME', 61);/*** replace XML entities*/define('XML_UTIL_REPLACE_ENTITIES', 1);/*** embedd content in a CData Section*/define('XML_UTIL_CDATA_SECTION', 5);/*** do not replace entitites*/define('XML_UTIL_ENTITIES_NONE', 0);/*** replace all XML entitites* This setting will replace <, >, ", ' and &*/define('XML_UTIL_ENTITIES_XML', 1);/*** replace only required XML entitites* This setting will replace <, " and &*/define('XML_UTIL_ENTITIES_XML_REQUIRED', 2);/*** replace HTML entitites* @link http://www.php.net/htmlentities*/define('XML_UTIL_ENTITIES_HTML', 3);/*** Collapse all empty tags.*/define('XML_UTIL_COLLAPSE_ALL', 1);/*** Collapse only empty XHTML tags that have no end tag.*/define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2);/*** utility class for working with XML documents** @category XML* @package XML_Util* @author Stephan Schmidt <schst@php.net>* @copyright 2003-2008 Stephan Schmidt <schst@php.net>* @license http://opensource.org/licenses/bsd-license New BSD License* @version Release: 1.2.1* @link http://pear.php.net/package/XML_Util*/class XML_Util{/*** return API version** @return string $version API version* @access public* @static*/function apiVersion(){return '1.1';}/*** replace XML entities** With the optional second parameter, you may select, which* entities should be replaced.** <code>* require_once 'XML/Util.php';** // replace XML entites:* $string = XML_Util::replaceEntities('This string contains < & >.');* </code>** With the optional third parameter, you may pass the character encoding* <code>* require_once 'XML/Util.php';** // replace XML entites in UTF-8:* $string = XML_Util::replaceEntities(* 'This string contains < & > as well as ä, ö, ß, à and ê',* XML_UTIL_ENTITIES_HTML,* 'UTF-8'* );* </code>** @param string $string string where XML special chars* should be replaced* @param int $replaceEntities setting for entities in attribute values* (one of XML_UTIL_ENTITIES_XML,* XML_UTIL_ENTITIES_XML_REQUIRED,* XML_UTIL_ENTITIES_HTML)* @param string $encoding encoding value (if any)...* must be a valid encoding as determined* by the htmlentities() function** @return string string with replaced chars* @access public* @static* @see reverseEntities()*/function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML,$encoding = 'ISO-8859-1'){switch ($replaceEntities) {case XML_UTIL_ENTITIES_XML:return strtr($string, array('&' => '&','>' => '>','<' => '<','"' => '"','\'' => ''' ));break;case XML_UTIL_ENTITIES_XML_REQUIRED:return strtr($string, array('&' => '&','<' => '<','"' => '"' ));break;case XML_UTIL_ENTITIES_HTML:return htmlentities($string, ENT_COMPAT, $encoding);break;}return $string;}/*** reverse XML entities** With the optional second parameter, you may select, which* entities should be reversed.** <code>* require_once 'XML/Util.php';** // reverse XML entites:* $string = XML_Util::reverseEntities('This string contains < & >.');* </code>** With the optional third parameter, you may pass the character encoding* <code>* require_once 'XML/Util.php';** // reverse XML entites in UTF-8:* $string = XML_Util::reverseEntities(* 'This string contains < & > as well as'* . ' ä, ö, ß, à and ê',* XML_UTIL_ENTITIES_HTML,* 'UTF-8'* );* </code>** @param string $string string where XML special chars* should be replaced* @param int $replaceEntities setting for entities in attribute values* (one of XML_UTIL_ENTITIES_XML,* XML_UTIL_ENTITIES_XML_REQUIRED,* XML_UTIL_ENTITIES_HTML)* @param string $encoding encoding value (if any)...* must be a valid encoding as determined* by the html_entity_decode() function** @return string string with replaced chars* @access public* @static* @see replaceEntities()*/function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML,$encoding = 'ISO-8859-1'){switch ($replaceEntities) {case XML_UTIL_ENTITIES_XML:return strtr($string, array('&' => '&','>' => '>','<' => '<','"' => '"',''' => '\'' ));break;case XML_UTIL_ENTITIES_XML_REQUIRED:return strtr($string, array('&' => '&','<' => '<','"' => '"' ));break;case XML_UTIL_ENTITIES_HTML:return html_entity_decode($string, ENT_COMPAT, $encoding);break;}return $string;}/*** build an xml declaration** <code>* require_once 'XML/Util.php';** // get an XML declaration:* $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true);* </code>** @param string $version xml version* @param string $encoding character encoding* @param bool $standalone document is standalone (or not)** @return string xml declaration* @access public* @static* @uses attributesToString() to serialize the attributes of the XML declaration*/function getXMLDeclaration($version = '1.0', $encoding = null,$standalone = null){$attributes = array('version' => $version,);// add encodingif ($encoding !== null) {$attributes['encoding'] = $encoding;}// add standalone, if specifiedif ($standalone !== null) {$attributes['standalone'] = $standalone ? 'yes' : 'no';}return sprintf('<?xml%s?>',XML_Util::attributesToString($attributes, false));}/*** build a document type declaration** <code>* require_once 'XML/Util.php';** // get a doctype declaration:* $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd');* </code>** @param string $root name of the root tag* @param string $uri uri of the doctype definition* (or array with uri and public id)* @param string $internalDtd internal dtd entries** @return string doctype declaration* @access public* @static* @since 0.2*/function getDocTypeDeclaration($root, $uri = null, $internalDtd = null){if (is_array($uri)) {$ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']);} elseif (!empty($uri)) {$ref = sprintf(' SYSTEM "%s"', $uri);} else {$ref = '';}if (empty($internalDtd)) {return sprintf('<!DOCTYPE %s%s>', $root, $ref);} else {return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);}}/*** create string representation of an attribute list** <code>* require_once 'XML/Util.php';** // build an attribute string* $att = array(* 'foo' => 'bar',* 'argh' => 'tomato'* );** $attList = XML_Util::attributesToString($att);* </code>** @param array $attributes attribute array* @param bool|array $sort sort attribute list alphabetically,* may also be an assoc array containing* the keys 'sort', 'multiline', 'indent',* 'linebreak' and 'entities'* @param bool $multiline use linebreaks, if more than* one attribute is given* @param string $indent string used for indentation of* multiline attributes* @param string $linebreak string used for linebreaks of* multiline attributes* @param int $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)** @return string string representation of the attributes* @access public* @static* @uses replaceEntities() to replace XML entities in attribute values* @todo allow sort also to be an options array*/function attributesToString($attributes, $sort = true, $multiline = false,$indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML){/** second parameter may be an array*/if (is_array($sort)) {if (isset($sort['multiline'])) {$multiline = $sort['multiline'];}if (isset($sort['indent'])) {$indent = $sort['indent'];}if (isset($sort['linebreak'])) {$multiline = $sort['linebreak'];}if (isset($sort['entities'])) {$entities = $sort['entities'];}if (isset($sort['sort'])) {$sort = $sort['sort'];} else {$sort = true;}}$string = '';if (is_array($attributes) && !empty($attributes)) {if ($sort) {ksort($attributes);}if ( !$multiline || count($attributes) == 1) {foreach ($attributes as $key => $value) {if ($entities != XML_UTIL_ENTITIES_NONE) {if ($entities === XML_UTIL_CDATA_SECTION) {$entities = XML_UTIL_ENTITIES_XML;}$value = XML_Util::replaceEntities($value, $entities);}$string .= ' ' . $key . '="' . $value . '"';}} else {$first = true;foreach ($attributes as $key => $value) {if ($entities != XML_UTIL_ENTITIES_NONE) {$value = XML_Util::replaceEntities($value, $entities);}if ($first) {$string .= ' ' . $key . '="' . $value . '"';$first = false;} else {$string .= $linebreak . $indent . $key . '="' . $value . '"';}}}}return $string;}/*** Collapses empty tags.** @param string $xml XML* @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL)* or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.** @return string XML* @access public* @static* @todo PEAR CS - unable to avoid "space after open parens" error* in the IF branch*/function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL){if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) {return preg_replace('/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|'. 'param)([^>]*)><\/\\1>/s','<\\1\\2 />',$xml);} else {return preg_replace('/<(\w+)([^>]*)><\/\\1>/s', '<\\1\\2 />', $xml);}}/*** create a tag** This method will call XML_Util::createTagFromArray(), which* is more flexible.** <code>* require_once 'XML/Util.php';** // create an XML tag:* $tag = XML_Util::createTag('myNs:myTag',* array('foo' => 'bar'),* 'This is inside the tag',* 'http://www.w3c.org/myNs#');* </code>** @param string $qname qualified tagname (including namespace)* @param array $attributes array containg attributes* @param mixed $content the content* @param string $namespaceUri URI of the namespace* @param int $replaceEntities whether to replace XML special chars in* content, embedd it in a CData section* or none of both* @param bool $multiline whether to create a multiline tag where* each attribute gets written to a single line* @param string $indent string used to indent attributes* (_auto indents attributes so they start* at the same column)* @param string $linebreak string used for linebreaks* @param bool $sortAttributes Whether to sort the attributes or not** @return string XML tag* @access public* @static* @see createTagFromArray()* @uses createTagFromArray() to create the tag*/function createTag($qname, $attributes = array(), $content = null,$namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,$multiline = false, $indent = '_auto', $linebreak = "\n",$sortAttributes = true){$tag = array('qname' => $qname,'attributes' => $attributes);// add tag contentif ($content !== null) {$tag['content'] = $content;}// add namespace Uriif ($namespaceUri !== null) {$tag['namespaceUri'] = $namespaceUri;}return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline,$indent, $linebreak, $sortAttributes);}/*** create a tag from an array* this method awaits an array in the following format* <pre>* array(* // qualified name of the tag* 'qname' => $qname** // namespace prefix (optional, if qname is specified or no namespace)* 'namespace' => $namespace** // local part of the tagname (optional, if qname is specified)* 'localpart' => $localpart,** // array containing all attributes (optional)* 'attributes' => array(),** // tag content (optional)* 'content' => $content,** // namespaceUri for the given namespace (optional)* 'namespaceUri' => $namespaceUri* )* </pre>** <code>* require_once 'XML/Util.php';** $tag = array(* 'qname' => 'foo:bar',* 'namespaceUri' => 'http://foo.com',* 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),* 'content' => 'I\'m inside the tag',* );* // creating a tag with qualified name and namespaceUri* $string = XML_Util::createTagFromArray($tag);* </code>** @param array $tag tag definition* @param int $replaceEntities whether to replace XML special chars in* content, embedd it in a CData section* or none of both* @param bool $multiline whether to create a multiline tag where each* attribute gets written to a single line* @param string $indent string used to indent attributes* (_auto indents attributes so they start* at the same column)* @param string $linebreak string used for linebreaks* @param bool $sortAttributes Whether to sort the attributes or not** @return string XML tag* @access public* @static* @see createTag()* @uses attributesToString() to serialize the attributes of the tag* @uses splitQualifiedName() to get local part and namespace of a qualified name* @uses createCDataSection()* @uses raiseError()*/function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,$multiline = false, $indent = '_auto', $linebreak = "\n",$sortAttributes = true){if (isset($tag['content']) && !is_scalar($tag['content'])) {return XML_Util::raiseError('Supplied non-scalar value as tag content',XML_UTIL_ERROR_NON_SCALAR_CONTENT);}if (!isset($tag['qname']) && !isset($tag['localPart'])) {return XML_Util::raiseError('You must either supply a qualified name '. '(qname) or local tag name (localPart).',XML_UTIL_ERROR_NO_TAG_NAME);}// if no attributes hav been set, use empty attributesif (!isset($tag['attributes']) || !is_array($tag['attributes'])) {$tag['attributes'] = array();}if (isset($tag['namespaces'])) {foreach ($tag['namespaces'] as $ns => $uri) {$tag['attributes']['xmlns:' . $ns] = $uri;}}if (!isset($tag['qname'])) {// qualified name is not given// check for namespaceif (isset($tag['namespace']) && !empty($tag['namespace'])) {$tag['qname'] = $tag['namespace'] . ':' . $tag['localPart'];} else {$tag['qname'] = $tag['localPart'];}} elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) {// namespace URI is set, but no namespace$parts = XML_Util::splitQualifiedName($tag['qname']);$tag['localPart'] = $parts['localPart'];if (isset($parts['namespace'])) {$tag['namespace'] = $parts['namespace'];}}if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) {// is a namespace givenif (isset($tag['namespace']) && !empty($tag['namespace'])) {$tag['attributes']['xmlns:' . $tag['namespace']] =$tag['namespaceUri'];} else {// define this Uri as the default namespace$tag['attributes']['xmlns'] = $tag['namespaceUri'];}}// check for multiline attributesif ($multiline === true) {if ($indent === '_auto') {$indent = str_repeat(' ', (strlen($tag['qname'])+2));}}// create attribute list$attList = XML_Util::attributesToString($tag['attributes'],$sortAttributes, $multiline, $indent, $linebreak, $replaceEntities);if (!isset($tag['content']) || (string)$tag['content'] == '') {$tag = sprintf('<%s%s />', $tag['qname'], $attList);} else {switch ($replaceEntities) {case XML_UTIL_ENTITIES_NONE:break;case XML_UTIL_CDATA_SECTION:$tag['content'] = XML_Util::createCDataSection($tag['content']);break;default:$tag['content'] = XML_Util::replaceEntities($tag['content'],$replaceEntities);break;}$tag = sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'],$tag['qname']);}return $tag;}/*** create a start element** <code>* require_once 'XML/Util.php';** // create an XML start element:* $tag = XML_Util::createStartElement('myNs:myTag',* array('foo' => 'bar') ,'http://www.w3c.org/myNs#');* </code>** @param string $qname qualified tagname (including namespace)* @param array $attributes array containg attributes* @param string $namespaceUri URI of the namespace* @param bool $multiline whether to create a multiline tag where each* attribute gets written to a single line* @param string $indent string used to indent attributes (_auto indents* attributes so they start at the same column)* @param string $linebreak string used for linebreaks* @param bool $sortAttributes Whether to sort the attributes or not** @return string XML start element* @access public* @static* @see createEndElement(), createTag()*/function createStartElement($qname, $attributes = array(), $namespaceUri = null,$multiline = false, $indent = '_auto', $linebreak = "\n",$sortAttributes = true){// if no attributes hav been set, use empty attributesif (!isset($attributes) || !is_array($attributes)) {$attributes = array();}if ($namespaceUri != null) {$parts = XML_Util::splitQualifiedName($qname);}// check for multiline attributesif ($multiline === true) {if ($indent === '_auto') {$indent = str_repeat(' ', (strlen($qname)+2));}}if ($namespaceUri != null) {// is a namespace givenif (isset($parts['namespace']) && !empty($parts['namespace'])) {$attributes['xmlns:' . $parts['namespace']] = $namespaceUri;} else {// define this Uri as the default namespace$attributes['xmlns'] = $namespaceUri;}}// create attribute list$attList = XML_Util::attributesToString($attributes, $sortAttributes,$multiline, $indent, $linebreak);$element = sprintf('<%s%s>', $qname, $attList);return $element;}/*** create an end element** <code>* require_once 'XML/Util.php';** // create an XML start element:* $tag = XML_Util::createEndElement('myNs:myTag');* </code>** @param string $qname qualified tagname (including namespace)** @return string XML end element* @access public* @static* @see createStartElement(), createTag()*/function createEndElement($qname){$element = sprintf('</%s>', $qname);return $element;}/*** create an XML comment** <code>* require_once 'XML/Util.php';** // create an XML start element:* $tag = XML_Util::createComment('I am a comment');* </code>** @param string $content content of the comment** @return string XML comment* @access public* @static*/function createComment($content){$comment = sprintf('<!-- %s -->', $content);return $comment;}/*** create a CData section** <code>* require_once 'XML/Util.php';** // create a CData section* $tag = XML_Util::createCDataSection('I am content.');* </code>** @param string $data data of the CData section** @return string CData section with content* @access public* @static*/function createCDataSection($data){return sprintf('<![CDATA[%s]]>',preg_replace('/\]\]>/', ']]]]><![CDATA[>', strval($data)));}/*** split qualified name and return namespace and local part** <code>* require_once 'XML/Util.php';** // split qualified tag* $parts = XML_Util::splitQualifiedName('xslt:stylesheet');* </code>* the returned array will contain two elements:* <pre>* array(* 'namespace' => 'xslt',* 'localPart' => 'stylesheet'* );* </pre>** @param string $qname qualified tag name* @param string $defaultNs default namespace (optional)** @return array array containing namespace and local part* @access public* @static*/function splitQualifiedName($qname, $defaultNs = null){if (strstr($qname, ':')) {$tmp = explode(':', $qname);return array('namespace' => $tmp[0],'localPart' => $tmp[1]);}return array('namespace' => $defaultNs,'localPart' => $qname);}/*** check, whether string is valid XML name** <p>XML names are used for tagname, attribute names and various* other, lesser known entities.</p>* <p>An XML name may only consist of alphanumeric characters,* dashes, undescores and periods, and has to start with a letter* or an underscore.</p>** <code>* require_once 'XML/Util.php';** // verify tag name* $result = XML_Util::isValidName('invalidTag?');* if (is_a($result, 'PEAR_Error')) {* print 'Invalid XML name: ' . $result->getMessage();* }* </code>** @param string $string string that should be checked** @return mixed true, if string is a valid XML name, PEAR error otherwise* @access public* @static* @todo support for other charsets* @todo PEAR CS - unable to avoid 85-char limit on second preg_match*/function isValidName($string){// check for invalid charsif (!preg_match('/^[[:alpha:]_]$/', $string{0})) {return XML_Util::raiseError('XML names may only start with letter '. 'or underscore', XML_UTIL_ERROR_INVALID_START);}// check for invalid charsif (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/',$string)) {return XML_Util::raiseError('XML names may only contain alphanumeric '. 'chars, period, hyphen, colon and underscores',XML_UTIL_ERROR_INVALID_CHARS);}// XML name is validreturn true;}/*** replacement for XML_Util::raiseError** Avoids the necessity to always require* PEAR.php** @param string $msg error message* @param int $code error code** @return PEAR_Error* @access public* @static* @todo PEAR CS - should this use include_once instead?*/function raiseError($msg, $code){require_once 'PEAR.php';return PEAR::raiseError($msg, $code);}}?>