pax_global_header00006660000000000000000000000064131254356500014516gustar00rootroot0000000000000052 comment=6e8203e40a32a9c770bcb62fe37e68b948da6dca fDOMDocument-1.6.6/000077500000000000000000000000001312543565000140145ustar00rootroot00000000000000fDOMDocument-1.6.6/.gitignore000066400000000000000000000001461312543565000160050ustar00rootroot00000000000000.buildpath .project .settings /fDOMDocument-1.1.0.tgz .idea build composer.lock composer.phar vendor/ fDOMDocument-1.6.6/.travis.yml000066400000000000000000000007171312543565000161320ustar00rootroot00000000000000language: php sudo: false php: - "5.3" - "5.4" - "5.5" - "5.6" - "7.0" - "7.1" - nightly # - hhvm matrix: allow_failures: - php: nightly # - php: hhvm fast_finish: true cache: directories: - $HOME/.composer/cache notifications: email: false before_script: - composer self-update - composer install - composer require --dev "phpunit/phpunit ^4.8.35|^5.6|^6.0" script: - vendor/bin/phpunit --verbose fDOMDocument-1.6.6/LICENSE000066400000000000000000000027631312543565000150310ustar00rootroot00000000000000fDOMDocument Copyright (c) 2010-2012 Arne Blankerts 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. * Neither the name of Arne Blankerts nor the names of contributors may 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 HOLDER ORCONTRIBUTORS 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. fDOMDocument-1.6.6/README.md000066400000000000000000000126201312543565000152740ustar00rootroot00000000000000fDOMDocument ============ The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM. [![Build Status](https://travis-ci.org/theseer/fDOMDocument.png)](https://travis-ci.org/theseer/fDOMDocument) Requirements ------------ PHP: 5.3.3 (5.3.0-5.3.2 had serious issues with spl stacked autoloaders) Extensions: dom, libxml Installation ------------ Apart from cloning this repository, fDOMDocument can be installed using by any of the following methods. ##### Composer As fDOMDocument is a library and does not provide any cli tools, you can only add it to your own project: { "require": { "theseer/fdomdocument": "^1.6" } } ##### YUM/DNF (Fedora / Redhat / CentOS) The following command will install fDOMDocument via its RPM package: sudo yum install php-theseer-fDOMDocument Usage ----- fDOMDocument is designed as a drop in replacement for DOMDocument. You can either use the composer generated autoloader or the provided one. Usage Samples ------------- loadXML(''); } catch (fDOMException $e) { die($e); } $child = $dom->queryOne('//child'); print_r($child->getAttribute('name')); print_r($child->getAttribute('missing','DefaultValue')); ?> Changelog --------- ##### Release 1.6.6 * Merge PRs 33+34: Add support for parameter "asTextNode" to fDOMElement::appendElement(). fDOMElement::appendElementNS() and fDOMElement::appendElementPrefix ##### Releaes 1.6.5 * Revert git exports limitations as they cause unwanted side effects ##### Releaes 1.6.4 * Merge PR 31 to optimize travis builds and git exports (Thanks to @willemstuursma) ##### Releaes 1.6.3 * Merge PR 29 to fix issues with PHP 7.2 ##### Release 1.6.2 * Handle empty string warings from PHP ##### Release 1.6.1 * Added Workaround for [HHVM Issue #5412](https://github.com/facebook/hhvm/issues/5412) ##### Release 1.6.0 * Added ```createElement*``` to ```fDOMEmenet``` and ```fDOMDocumentFragment``` as shortcuts * Added ```appendElement*``` to ```fDOMDocumentFragment``` as shortcuts * Enhanced the exception messages of save errors with filenames to contain the filename * Fixed fDomDocumentFragment::__toString to actually work * Updated / Added some tests ##### Release 1.5.0 * Added ```select``` to ```fDOMDocument```,```fDOMElement``` and ```fDOMNode``` to support CSS Selectors in favor of XPath only to find nodes * Added ```query``` and ```queryOne``` forwardes to ```fDOMNode``` ##### Release 1.4.3 * Added ```saveXML``` and ```saveHTML``` to ```fDOMNode``` and ```fDOMElement``` as a shortcut to calling those methods on the ownerDocument ##### Release 1.4.2 * Added ```__toString``` support to ```fDOMNode```, ```fDOMElement```, ```fDOMDocument``` and ```fDOMDocumentFragment``` ##### Release 1.4.1 * Removed unused Interface ```fDOMNodeInterface``` from code base ##### Release 1.4.0 * Added XPathQuery helper object, allowing for a prepared statement alike API around XPath ##### Release 1.3.2 * Added ```__clone``` method to reset domxpath object when domdocument gets cloned (Thanks to Markus Ineichen for pointing it out) ##### Release 1.3.1 * PHP 5.3 compatibility: changed interal behavior for incompatible changes from PHP 5.3 to 5.4 (Thanks to Jens Graefe for pointing it out) ##### Release 1.3.0 * Added appendTextNode method (Thanks to Markus Ineichen) * Added appendElement / appendElementNS to DOMDocument to support documentElement "creation" (Thanks to Markus Ineichen) * Overwrite createElement / createElementNS to throw exception on error * Removed fDOMFilter code: Unmaintained and broken in its current form * Added (static) Flag for fDOMException to globally enable full exception message * Added Unit tests ##### Release 1.2.4 * PHP 5.4 compatibilty: added support for optional options bitmask on additional methods ##### Release 1.2.3 * Cleanup code style to adhere coding standard * Added entity support for Attributes * Added phpcs file to make coding standard public ##### Release 1.2.2 * Fix Exception to not overwrite final methods of \Exception ##### Release 1.2.1 * Changed fDOMDocument to be no longer final, use lsb to lookup actual class in constructor. This should fix test/mock issues. ##### Release 1.2.0 * Changed fException to be more compatible with standard exceptions by adding a switch to get full info by getMessage() * Merged setAttributes() and setAttributesNS() methods from Andreas * Fixed internal registerNamespace variable mixup ##### Release 1.1.0 * Renamed files to mimic classname cases * Fixed inSameDocument to support DOMDocument as well as DOMNodes * Added fDOMXPath class providing queryOne(), qoute() and prepare() * Adjusted forwarders in fDOMDocument to make use of new object * Fixed various return values to statically return true for compatibility with original API * Applied Workaround to fix potential problems with lost references to instances of fDOMDocument * Support registerPHPFunctions * Bump Copyright * Added missing docblocks ##### Release 1.0.2 * Indenting and typo fixes, minor bugfixes ##### Release 1.0.1 * Bugfix: typehints corrected ##### Release 1.0.0 * Initial release fDOMDocument-1.6.6/build.xml000066400000000000000000000060441312543565000156410ustar00rootroot00000000000000 fDOMDocument-1.6.6/composer.json000066400000000000000000000014641312543565000165430ustar00rootroot00000000000000{ "name": "theseer/fdomdocument", "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", "license": "BSD-3-Clause", "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "lead" } ], "support": { "issues": "https://github.com/theseer/fDOMDocument/issues" }, "require": { "php": ">=5.3.3", "ext-dom": "*", "lib-libxml": "*" }, "autoload": { "classmap": [ "src/" ] } } fDOMDocument-1.6.6/fDOMDocument.spec000066400000000000000000000047321312543565000171620ustar00rootroot00000000000000%define _pearDir /usr/share/pear/ %define _sourcedir src/ Summary: fDOMDocument - An Extension to PHP's standard DOM to add various convenience methods and exceptions by default Name: fDOMDocument Version: 1.1.0 Release: 1 Group: System Environment/Libraries License: Arne Blankerts Vendor: Arne Blankerts URL: https://github.com/theseer/ #Source: Provides: fDOMDocument-%{version}%{release} BuildRoot: %{_tmppath}/%{name}-%{version}%{release}-root-%(%{__id_u} -n) BuildArch: noarch Requires: php-common, php-dom %description fDOMDocument - An Extension to PHP's standard DOM to add various convenience methods and exceptions by default %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT install -m 755 -d $RPM_BUILD_ROOT%{_pearDir}TheSeer install -m 755 -d $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument install -m 755 -d $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMFilter cp %{_sourcedir}fDOMDocument.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMDocument.php cp %{_sourcedir}fDOMDocumentFragment.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMDocumentFragment.php cp %{_sourcedir}fDOMElement.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMElement.php cp %{_sourcedir}fDOMException.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMException.php cp %{_sourcedir}fDOMFilter.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMFilter.php cp %{_sourcedir}fDOMNode.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMNode.php cp %{_sourcedir}fDOMXPath.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMXPath.php cp %{_sourcedir}fDOMFilter/xhtml.php $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/fDOMFilter/xhtml.php phpab -o $RPM_BUILD_ROOT%{_pearDir}TheSeer/fDOMDocument/autoload.php TheSeer/fDOMDocument %post %files %defattr(-,root,root) %dir %{_pearDir}TheSeer/fDOMDocument %dir %{_pearDir}TheSeer/fDOMDocument/fDOMFilter %{_pearDir}TheSeer/fDOMDocument/* %{_pearDir}TheSeer/fDOMDocument/fDOMFilter/* %{_pearDir}TheSeer/fDOMDocument/autoload.php %{_pearDir}TheSeer/fDOMDocument/fDOMDocument.php %{_pearDir}TheSeer/fDOMDocument/fDOMDocumentFragment.php %{_pearDir}TheSeer/fDOMDocument/fDOMElement.php %{_pearDir}TheSeer/fDOMDocument/fDOMException.php %{_pearDir}TheSeer/fDOMDocument/fDOMFilter.php %{_pearDir}TheSeer/fDOMDocument/fDOMNode.php %{_pearDir}TheSeer/fDOMDocument/fDOMXPath.php %{_pearDir}TheSeer/fDOMDocument/fDOMFilter/xhtml.php %changelog * Tue Jul 04 2011 Maik 'M4ikT' Thieme 1.1.0 - Initial package release fDOMDocument-1.6.6/phpcs.xml000066400000000000000000000026161312543565000156600ustar00rootroot00000000000000 Arne Blankerts' coding standard fDOMDocument-1.6.6/phpunit.xml.dist000066400000000000000000000016151312543565000171720ustar00rootroot00000000000000 tests src src/bootstrap fDOMDocument-1.6.6/src/000077500000000000000000000000001312543565000146035ustar00rootroot00000000000000fDOMDocument-1.6.6/src/XPathQuery.php000066400000000000000000000142541312543565000173740ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { /** * Class XPathQuery * * @package TheSeer\fDOM */ class XPathQuery { /** * @var string */ private $query; /** * Key-value Map for bound values * * @var array */ private $values = array(); /** * @param string $query */ public function __construct($query) { $this->setQuery($query); } /** * Set Query. * * @param string $query */ private function setQuery($query) { $this->query = $query; $res = preg_match_all('/(:(\w*))/', $query, $matches); if ($res > 0) { $this->values = array_fill_keys($matches[2], ''); } } /** * Returns keys. * * @return array */ public function getKeys() { return array_keys($this->values); } /** * Bind value to key. * * @param string $key * @param string $value * * @throws XPathQueryException */ public function bind($key, $value) { if (!array_key_exists($key, $this->values)) { throw new XPathQueryException("'$key' not found in query'", XPathQueryException::KeyNotFound ); } $this->values[$key] = $value; } /** * Generate query. * * @param \DOMNode $ctx * @param array $values * * @return string */ public function generate(\DOMNode $ctx, array $values = NULL) { return $this->buildQuery($this->getXPathObjectFor($ctx), $values); } /** * Evaluate Query. * * @param \DOMNode $ctx * @param array $values * @param bool $registerNodeNS * * @throws fDOMException * * @return mixed */ public function evaluate(\DOMNode $ctx, array $values = NULL, $registerNodeNS = TRUE) { $xp = $this->getXPathObjectFor($ctx); return $xp->evaluate($this->buildQuery($xp, $values), $ctx, $registerNodeNS); } /** * Execute Query. * * @param \DOMNode $ctx * @param array $values * @param bool $registerNodeNS * * @throws fDOMException * * @return mixed */ public function query(\DOMNode $ctx, array $values = NULL, $registerNodeNS = TRUE) { $xp = $this->getXPathObjectFor($ctx); return $xp->evaluate($this->buildQuery($xp, $values), $ctx, $registerNodeNS); } /** * Execute Query and return first result. * * @param \DOMNode $ctx * @param array $values * @param bool $registerNodeNS * * @return \DOMNode */ public function queryOne(\DOMNode $ctx, array $values = NULL, $registerNodeNS = TRUE) { $xp = $this->getXPathObjectFor($ctx); return $xp->queryOne($this->buildQuery($xp, $values), $ctx, $registerNodeNS); } /** * Return xPath for node * * @param \DOMNode $ctx * * @throws fDOMException * * @return fDOMXPath */ private function getXPathObjectFor(\DOMNode $ctx) { $dom = $ctx instanceof \DOMDocument ? $ctx : $ctx->ownerDocument; if ($dom instanceOf fDOMDocument) { return $dom->getDOMXPath(); } return new fDOMXPath($dom); } /** * Build query using values. * * @param fDOMXPath $xp * @param array $values * * @throws XPathQueryException * * @return string */ private function buildQuery(fDOMXPath $xp, array $values = NULL) { $backup = $this->values; if (is_array($values) && count($values) > 0) { foreach($values as $k => $v) { $this->bind($k, $v); } } $query = $xp->prepare($this->query, $this->values); $this->values = $backup; return $query; } } } fDOMDocument-1.6.6/src/XPathQueryException.php000066400000000000000000000037701312543565000212540ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { class XPathQueryException extends \Exception { const KeyNotFound = 1; } } fDOMDocument-1.6.6/src/autoload.php000066400000000000000000000026761312543565000171370ustar00rootroot00000000000000 '/css/DollarEqualRule.php', 'theseer\\fdom\\css\\notrule' => '/css/NotRule.php', 'theseer\\fdom\\css\\nthchildrule' => '/css/NthChildRule.php', 'theseer\\fdom\\css\\regexrule' => '/css/RegexRule.php', 'theseer\\fdom\\css\\ruleinterface' => '/css/RuleInterface.php', 'theseer\\fdom\\css\\translator' => '/css/Translator.php', 'theseer\\fdom\\fdomdocument' => '/fDOMDocument.php', 'theseer\\fdom\\fdomdocumentfragment' => '/fDOMDocumentFragment.php', 'theseer\\fdom\\fdomelement' => '/fDOMElement.php', 'theseer\\fdom\\fdomexception' => '/fDOMException.php', 'theseer\\fdom\\fdomnode' => '/fDOMNode.php', 'theseer\\fdom\\fdomxpath' => '/fDOMXPath.php', 'theseer\\fdom\\xpathquery' => '/XPathQuery.php', 'theseer\\fdom\\xpathqueryexception' => '/XPathQueryException.php' ); } $cn = strtolower($class); if (isset($classes[$cn])) { require __DIR__ . $classes[$cn]; } } ); // @codeCoverageIgnoreEnd fDOMDocument-1.6.6/src/css/000077500000000000000000000000001312543565000153735ustar00rootroot00000000000000fDOMDocument-1.6.6/src/css/DollarEqualRule.php000066400000000000000000000014051312543565000211410ustar00rootroot00000000000000translator = $translator; } /** * @param $selector * * @return string */ public function apply($selector) { return preg_replace_callback( '/([a-zA-Z0-9\_\-\*]+):not\(([^\)]*)\)/', array($this, 'callback'), $selector ); } /** * @param array $matches * * @return string */ private function callback(array $matches) { $subresult = preg_replace( '/^[^\[]+\[([^\]]*)\].*$/', '$1', $this->translator->translate($matches[2]) ); return $matches[1] . '[not(' . $subresult . ')]'; } } } fDOMDocument-1.6.6/src/css/NthChildRule.php000066400000000000000000000027111312543565000204320ustar00rootroot00000000000000=0]/self::' . $matches[1]; } case 'odd': { return $matches[1] . '[(count(preceding-sibling::*) + 1) mod 2=1]'; } default: { $b = !isset($matches[2]) || empty($matches[2]) ? '0' : $matches[2]; $b = preg_replace('/^([0-9]*)n.*?([0-9]*)$/', '$1+$2', $b); $b = explode('+', $b); if (!isset($b[1])) { $b[1] = '0'; } return '*[(position()-' . $b[1] . ') mod ' . $b[0] . '=0 and position()>=' . $b[1] . ']/self::' . $matches[1]; } } } } } fDOMDocument-1.6.6/src/css/RegexRule.php000066400000000000000000000013071312543565000200070ustar00rootroot00000000000000regex = $regex; $this->replacement = $replacement; } /** * @param $selector * * @return string */ public function apply($selector) { return preg_replace($this->regex, $this->replacement, $selector); } } } fDOMDocument-1.6.6/src/css/RuleInterface.php000066400000000000000000000003201312543565000206270ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM\CSS { /** * Class Translator * * The regular expressions used in this class are heavily inspired by and mostly adopted from * the css2xpath.js code by Andrea Giammarchi (http://code.google.com/p/css2xpath/). * The JavaScript version (css2xpath.js) is licensed under the MIT License * */ class Translator { /** * @var array */ private $rules; /** * @param string $selector A CSS Selector string * * @return string */ public function translate($selector) { foreach($this->getRules() as $rule) { /** @var RuleInterface $rule */ $selector = $rule->apply($selector); } return '//' . $selector; } /** * @return array */ private function getRules() { if ($this->rules != NULL) { return $this->rules; } $this->rules = array( // prefix|name new RegexRule('/([a-zA-Z0-9\_\-\*]+)\|([a-zA-Z0-9\_\-\*]+)/', '$1:$2'), // add @ for attribs new RegexRule("/\[([^\]~\$\*\^\|\!]+)(=[^\]]+)?\]/", '[@$1$2]'), // multiple queries new RegexRule("/\s*,\s*/", '|'), // , + ~ > new RegexRule("/\s*(\+|~|>)\s*/", '$1'), //* ~ + > new RegexRule("/([a-zA-Z0-9\_\-\*])~([a-zA-Z0-9\_\-\*])/", '$1/following-sibling::$2'), new RegexRule("/([a-zA-Z0-9\_\-\*])\+([a-zA-Z0-9\_\-\*])/", '$1/following-sibling::*[1]/self::$2'), new RegexRule("/([a-zA-Z0-9\_\-\*])>([a-zA-Z0-9\_\-\*])/", '$1/$2'), // all unescaped stuff escaped new RegexRule("/\[([^=]+)=([^'|'][^\]]*)\]/", '[$1="$2"]'), // all descendant or self to // new RegexRule("/(^|[^a-zA-Z0-9\_\-\*])(#|\.)([a-zA-Z0-9\_\-]+)/", '$1*$2$3'), new RegexRule("/([\>\+\|\~\,\s])([a-zA-Z\*]+)/", '$1//$2'), new RegexRule("/\s+\/\//", '//'), // :first-child new RegexRule("/([a-zA-Z0-9\_\-\*]+):first-child/", '*[1]/self::$1'), // :last-child new RegexRule("/([a-zA-Z0-9\_\-\*]+):last-child/", '$1[not(following-sibling::*)]'), // :only-child new RegexRule("/([a-zA-Z0-9\_\-\*]+):only-child/", '*[last()=1]/self::$1'), // :empty new RegexRule("/([a-zA-Z0-9\_\-\*]+):empty/", '$1[not(*) and not(normalize-space())]'), // :not new NotRule($this), // :nth-child new NthChildRule(), // :contains(selectors) new RegexRule('/:contains\(([^\)]*)\)/', '[contains(string(.),"$1")]'), // |= attrib new RegexRule("/\[([a-zA-Z0-9\_\-]+)\|=([^\]]+)\]/", '[@$1=$2 or starts-with(@$1,concat($2,"-"))]'), // *= attrib new RegexRule("/\[([a-zA-Z0-9\_\-]+)\*=([^\]]+)\]/", '[contains(@$1,$2)]'), // ~= attrib new RegexRule("/\[([a-zA-Z0-9\_\-]+)~=([^\]]+)\]/", '[contains(concat(" ",normalize-space(@$1)," "),concat(" ",$2," "))]'), // ^= attrib new RegexRule("/\[([a-zA-Z0-9\_\-]+)\^=([^\]]+)\]/", '[starts-with(@$1,$2)]'), // $= attrib new DollarEqualRule(), // != attrib new RegexRule("/\[([a-zA-Z0-9\_\-]+)\!=([^\]]+)\]/", '[not(@$1) or @$1!=$2]'), // ids and classes new RegexRule("/#([a-zA-Z0-9\_\-]+)/", '[@id="$1"]'), new RegexRule("/\.([a-zA-Z0-9\_\-]+)/", '[contains(concat(" ",normalize-space(@class)," ")," $1 ")]'), // normalize multiple filters new RegexRule("/\]\[([^\]]+)/", ' and ($1)') ); return $this->rules; } } } fDOMDocument-1.6.6/src/fDOMDocument.php000066400000000000000000000554421312543565000176120ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { use TheSeer\fDOM\CSS\Translator; /** * fDOMDocument extension to PHP's DOMDocument. * This class adds various convenience methods to simplify APIs * It is set to final since further extending it would even more * break the Object structure after use of registerNodeClass. * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * @property fDOMDocument $ownerDocument * */ class fDOMDocument extends \DOMDocument { /** * XPath Object instance * * @var fDOMXPath */ private $xp = NULL; /** * List of registered prefixes and their namespace uri * @var array */ private $prefixes = array(); /** * Extended DOMDocument constructor * * @param string $version XML Version, should be 1.0 * @param string $encoding Encoding, defaults to utf-8 * @param array $streamOptions optional stream options array * * @return fDOMDocument */ public function __construct($version = '1.0', $encoding = 'utf-8', $streamOptions = NULL) { if (!is_null($streamOptions)) { $this->setStreamContext($streamOptions); } libxml_use_internal_errors(TRUE); $rc = parent::__construct($version, $encoding); $this->registerNodeClasses(); return $rc; } /** * Reset XPath object so the clone gets a new instance when needed */ public function __clone() { $this->registerNodeClasses(); $this->xp = new fDOMXPath($this); foreach($this->prefixes as $prefix => $uri) { $this->xp->registerNamespace($prefix, $uri); } } /** * @return string */ public function __toString() { return $this->C14N(); } /** * Set Stream context options * * @param array $options Stream context options * * @return boolean true on success, false on failure */ public function setStreamContext(array $options) { if (!count($options)) { return FALSE; } $context = stream_context_create($options); libxml_set_streams_context($context); return TRUE; } /** * Wrapper to DOMDocument load with exception handling * Returns true on success to satisfy the compatibilty of the original DOM Api * * @param string $fname File to load * @param int|null $options LibXML Flags to pass * * @throws fDOMException * * @return bool|mixed */ public function load($fname, $options = LIBXML_NONET) { if ($fname === '') { throw new fDOMException('empty filename is not allowed', fDOMException::ParseError); } $this->xp = NULL; $tmp = parent :: load($fname, $options); if (!$tmp || libxml_get_last_error()) { throw new fDOMException("loading file '$fname' failed.", fDOMException::LoadError); } $this->registerNodeClasses(); return TRUE; } /** * Wrapper to DOMDocument loadXML with exception handling * Returns true on success to satisfy the compatibilty of the original DOM Api * * @param string $source XML source code * @param integer $options LibXML option flags * * @throws fDOMException * * @return boolean */ public function loadXML($source, $options = LIBXML_NONET) { if ($source === '') { throw new fDOMException('empty string not allowed', fDOMException::ParseError); } $this->xp = NULL; $tmp = parent :: loadXML($source, $options); if (!$tmp || libxml_get_last_error()) { throw new fDOMException('parsing string failed', fDOMException::ParseError); } $this->registerNodeClasses(); return TRUE; } /** * Wrapper to DOMDocument loadHTMLFile with exception handling. * Returns true on success to satisfy the compatibilty of the original DOM Api * * @param string $fname html file to load * @param integer $options Options bitmask (@see DOMDocument::loadHTMLFile) * * @throws fDOMException * * @return boolean */ public function loadHTMLFile($fname, $options = NULL) { if ($fname === '') { throw new fDOMException('empty filename is not allowed', fDOMException::ParseError); } $this->xp = NULL; if (version_compare(PHP_VERSION, '5.4.0', '<')) { if ($options !== NULL) { throw new fDOMException('Passing options requires PHP 5.4.0+', fDOMException::LoadError); } $tmp = parent :: loadHTMLFile($fname); } else { $tmp = parent :: loadHTMLFile($fname, $options); } if (!$tmp || libxml_get_last_error()) { throw new fDOMException("loading html file '$fname' failed", fDOMException::LoadError); } $this->registerNodeClasses(); return TRUE; } /** * Wrapper to DOMDocument loadHTML with exception handling * Returns true on success to satisfy the compatibilty of the original DOM Api * * @param string $source html source code * @param integer $options Options bitmask (@see DOMDocument::loadHTML) * * @throws fDOMException * * @return boolean */ public function loadHTML($source, $options = NULL) { if ($source === '') { throw new fDOMException('empty string not allowed', fDOMException::ParseError); } $this->xp = NULL; if (version_compare(PHP_VERSION, '5.4.0', '<')) { if ($options !== NULL) { throw new fDOMException('Passing options requires PHP 5.4.0+', fDOMException::LoadError); } $tmp = parent :: loadHTML($source); } else { $tmp = parent :: loadHTML($source, $options); } if (!$tmp || libxml_get_last_error()) { throw new fDOMException('parsing html string failed', fDOMException::ParseError); } $this->registerNodeClasses(); return TRUE; } /** * Wrapper to DOMDocument::save with exception handling * * @param string $filename filename to save to * @param integer $options Options bitmask (@see DOMDocument::save) * * @throws fDOMException * * @return integer bytes saved */ public function save($filename, $options = NULL) { $tmp = parent::save($filename, $options); if (!$tmp) { throw new fDOMException("Saving XML to file '$filename' failed", fDOMException::SaveError); } return $tmp; } /** * Wrapper to DOMDocument::saveHTML with exception handling * * @param \DOMNode|null $node Context DOMNode (optional) * * @throws fDOMException * * @return string html content */ public function saveHTML(\DOMNode $node = NULL) { if (version_compare(PHP_VERSION, '5.3.6', '<') && $node !== NULL) { throw new fDOMException('Passing a context node requires PHP 5.3.6+', fDOMException::SaveError); } $tmp = parent::saveHTML($node); if (!$tmp) { throw new fDOMException('Serializing to HTML failed', fDOMException::SaveError); } return $tmp; } /** * Wrapper to DOMDocument::saveHTMLfile with exception handling * * @param string $filename filename to save to * @param integer $options Options bitmask (@see DOMDocument::saveHTMLFile) * * @throws fDOMException * * @return integer bytes saved */ public function saveHTMLFile($filename, $options = NULL) { $tmp = parent::saveHTMLFile($filename, $options); if (!$tmp) { throw new fDOMException("Saving HTML to file '$filename' failed", fDOMException::SaveError); } return $tmp; } /** * Wrapper to DOMDocument::saveXML with exception handling * * @param \DOMNode $node node to start serializing at * @param integer $options options flags as bitmask * * @throws fDOMException * * @return string serialized XML */ public function saveXML(\DOMNode $node = NULL, $options = NULL) { try { $tmp = parent::saveXML($node, $options); if (!$tmp) { throw new fDOMException('Serializing to XML failed', fDOMException::SaveError); } return $tmp; } catch (\Exception $e) { if (!$e instanceof fDOMException) { throw new fDOMException($e->getMessage(), fDOMException::SaveError, $e); } throw $e; } } /** * get Instance of DOMXPath Object for current DOM * * @throws fDOMException * * @return fDOMXPath */ public function getDOMXPath() { if (is_null($this->xp)) { $this->xp = new fDOMXPath($this); } if (!$this->xp) { throw new fDOMException('creating DOMXPath object failed.', fDOMException::NoDOMXPath); } return $this->xp; } /** * Convert a given DOMNodeList into a DOMFragment * * @param \DOMNodeList $list The Nodelist to process * @param boolean $move Signale if nodes are to be moved into fragment or not * * @return fDOMDocumentFragment */ public function nodeList2Fragment(\DOMNodeList $list, $move=FALSE) { $frag = $this->createDocumentFragment(); /** @var fDOMNode $node */ foreach($list as $node) { $frag->appendChild($move ? $node : $node->cloneNode(TRUE)); } return $this->ensureIntance($frag); } /** * Perform an xpath query * * @param String $q query string containing xpath * @param \DOMNode|null $ctx (optional) Context DOMNode * @param boolean $registerNodeNS Register flag pass through * * @return \DOMNodeList */ public function query($q, \DOMNode $ctx = NULL, $registerNodeNS = TRUE) { if (is_null($this->xp)) { $this->getDOMXPath(); } return $this->xp->evaluate($q, $ctx, $registerNodeNS); } /** * Perform an xpath query and return only the 1st match * * @param String $q query string containing xpath * @param \DOMNode $ctx (optional) Context DOMNode * @param boolean $registerNodeNS Register flag pass thru * * @return fDOMNode */ public function queryOne($q, \DOMNode $ctx = NULL, $registerNodeNS = TRUE) { if (is_null($this->xp)) { $this->getDOMXPath(); } return $this->xp->queryOne($q, $ctx, $registerNodeNS); } /** * Forwarder to fDOMXPath's prepare method allowing for easy and secure * placeholder replacement comparable to sql's prepared statements * . * @param string $xpath String containing xpath with :placeholder markup * @param array $valueMap array containing keys (:placeholder) and value pairs to be quoted * * @return string */ public function prepareQuery($xpath, array $valueMap) { if (is_null($this->xp)) { $this->getDOMXPath(); } return $this->xp->prepare($xpath, $valueMap); } /** * Use a CSS Level 3 Selector string to query select nodes * * @param string $selector A CSS Level 3 Selector string * @param \DOMNode $ctx * @param bool $registerNodeNS * * @return \DOMNodeList */ public function select($selector, \DOMNode $ctx = NULL, $registerNodeNS = TRUE) { $translator = new Translator(); $xpath = $translator->translate($selector); if ($ctx !== NULL) { $xpath = '.' . $xpath; } return $this->query($xpath, $ctx, $registerNodeNS); } /** * Forward to DOMXPath->registerNamespace() * * @param string $prefix The prefix to use * @param string $uri The uri to assign to this prefix * * @throws fDOMException * * @return void */ public function registerNamespace($prefix, $uri) { if (is_null($this->xp)) { $this->getDOMXPath(); } if (!$this->xp->registerNamespace($prefix, $uri)) { throw new fDOMException("Registering namespace '$uri' with prefix '$prefix' failed.", fDOMException::RegistrationFailed); } $this->prefixes[$prefix] = $uri; } /** * Forward to DOMXPath->registerPHPFunctions() * * @param mixed $restrict array of function names or string with functionname to restrict callabilty to * * @throws fDOMException * * @return void */ public function registerPHPFunctions($restrict = NULL) { if (is_null($this->xp)) { $this->getDOMXPath(); } $this->xp->registerPHPFunctions($restrict); if (libxml_get_last_error()) { throw new fDOMException("Registering php functions failed.", fDOMException::RegistrationFailed); } } /** * Create a new element in namespace defined by given prefix * * @param string $prefix Namespace prefix for node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextNode Create content as textNode rather then setting nodeValue * * @throws fDOMException * * @return fDOMElement Reference to created fDOMElement */ public function createElementPrefix($prefix, $name, $content = NULL, $asTextNode = FALSE) { if (!isset($this->prefixes[$prefix])) { throw new fDOMException("'$prefix' not bound", fDOMException::UnboundPrefix); } return $this->createElementNS($this->prefixes[$prefix], $prefix.':'.$name, $content, $asTextNode); } /** * Create a new fDOMElement and return it, optionally set content * * @param string $name Name of node to create * @param null $content Content to set (optional) * @param bool $asTextnode Create content as textNode rather then setting nodeValue * * @throws fDOMException * * @return fDOMElement Reference to created fDOMElement */ public function createElement($name, $content = NULL, $asTextnode = FALSE) { try { $node = parent::createElement($name); if (!$node) { throw new fDOMException("Creating element with name '$name' failed", fDOMException::NameInvalid); } if ($content !== NULL) { if ($asTextnode) { $node->appendChild($this->createTextnode($content)); } else { $node->nodeValue = $content; } if (libxml_get_errors()) { throw new fDOMException("Setting content value failed", fDOMException::SetFailedError); } } return $this->ensureIntance($node); } catch (\DOMException $e) { throw new fDOMException("Creating elemnt with name '$name' failed", 0, $e); } } /** * Create a new fDOMElement within given namespace and return it * * @param string $namespace Namespace URI for node to create * @param string $name Name of node to create * @param string $content Content to set (optional) * @param bool $asTextNode Create content as textNode rather then setting nodeValue * * @throws fDOMException * * @return fDOMElement */ public function createElementNS($namespace, $name, $content = NULL, $asTextNode = FALSE) { $node = parent::createElementNS($namespace, $name); if (!$node) { throw new fDOMException("Creating element with name '$name' failed", fDOMException::NameInvalid); } if ($content !== NULL) { if ($asTextNode) { $node->appendChild($this->createTextnode($content)); } else { $node->nodeValue = $content; } if (libxml_get_errors()) { throw new fDOMException("Setting content value failed", fDOMException::SetFailedError); } } return $this->ensureIntance($node); } /** * @return fDOMDocumentFragment */ public function createDocumentFragment() { return $this->ensureIntance(parent::createDocumentFragment()); } /** * Check if the given node is in the same document * * @param \DOMNode $node Node to compare with * * @return boolean true on match, false if they differ * */ public function inSameDocument(\DOMNode $node) { if ($node instanceof \DOMDocument) { return $this->isSameNode($node); } return $this->isSameNode($node->ownerDocument); } /** * Create a new element and append it as documentElement * * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextNode * * @return fDOMElement Reference to created fDOMElement */ public function appendElement($name, $content = NULL, $asTextNode = FALSE) { return $this->appendChild( $this->createElement($name, $content, $asTextNode) ); } /** * Create a new element in given namespace and append it as documentElement * * @param string $ns Namespace of node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextNode * * @return fDOMElement Reference to created fDOMElement */ public function appendElementNS($ns, $name, $content = NULL, $asTextNode = FALSE) { return $this->appendChild( $this->createElementNS($ns, $name, $content, $asTextNode) ); } /** * This is a workaround for hhvm's broken registerNodeClass handling * (https://github.com/facebook/hhvm/issues/1848) * * @param \DOMNode $node * * @return \DOMNode */ private function ensureIntance(\DOMNode $node) { if ($node instanceof fDOMNode || $node instanceof fDOMElement || $node instanceof fDOMDocumentFragment) { return $node; } return $this->importNode($node, TRUE); } /** * Register replacements * * Called from constructor and, as a workaround for (https://github.com/facebook/hhvm/issues/5412), * after load(), loadXML(), loadHTML() and loadHTMLFile() */ private function registerNodeClasses() { $this->registerNodeClass('DOMDocument', get_called_class()); $this->registerNodeClass('DOMNode', 'TheSeer\fDOM\fDOMNode'); $this->registerNodeClass('DOMElement', 'TheSeer\fDOM\fDOMElement'); $this->registerNodeClass('DOMDocumentFragment', 'TheSeer\fDOM\fDOMDocumentFragment'); } } // fDOMDocument } fDOMDocument-1.6.6/src/fDOMDocumentFragment.php000066400000000000000000000155111312543565000212670ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { /** * fDOMDocumentFragment * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * @property fDOMDocument $ownerDocument * */ class fDOMDocumentFragment extends \DOMDocumentFragment { /** * @return string */ public function __toString() { return $this->ownerDocument->saveXML($this); } /** * Wrapper to standard method with exception support * * @param string $str Data string to parse and append * * @throws fDOMException * * @return bool true on success */ public function appendXML($str) { if (!parent::appendXML($str)) { throw new fDOMException('Appending xml string failed', fDOMException::ParseError); } return true; } /** * Create a new element and append it * * @param string $name Name of not element to create * @param string $content Optional content to be set * * @return fDOMElement Reference to created fDOMElement */ public function appendElement($name, $content = null) { $node = $this->ownerDocument->createElement($name, $content); $this->appendChild($node); return $node; } /** * Create a new element in given namespace and append it * * @param string $ns Namespace of node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * * @return fDOMElement Reference to created fDOMElement */ public function appendElementNS($ns, $name, $content = null) { $node = $this->ownerDocument->createElementNS($ns, $name, $content); $this->appendChild($node); return $node; } /** * Create a new element in given namespace and append it * * @param string $prefix Namespace prefix for node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextnode Create content as textNode rather then setting nodeValue * * @return fDOMElement Reference to created fDOMElement */ public function appendElementPrefix($prefix, $name, $content = null, $asTextnode = FALSE) { $node = $this->ownerDocument->createElementPrefix($prefix, $name, $content, $asTextnode); $this->appendChild($node); return $node; } /** * Create a new text node and append it * * @param string $content Text content to be added * * @return \DOMText */ public function appendTextNode($content) { $text = $this->ownerDocument->createTextNode($content); $this->appendChild($text); return $text; } /** * Check if the given node is in the same document * * @param \DOMNode $node Node to compare with * * @return boolean true on match, false if they differ * */ public function inSameDocument(\DOMNode $node) { return $this->ownerDocument->inSameDocument($node); } /** * Forward to fDomDocument->query() * * @param string $q XPath to use * @param \DOMNode $ctx \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return \DomNodeList */ public function query($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->query($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->queryOne() * * @param string $q XPath to use * @param \DOMNode $ctx (optional) \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return mixed */ public function queryOne($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->queryOne($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->select() * * @param string $selector A CSS Level 3 Selector string * @param \DOMNode $ctx * @param bool $registerNodeNS * * @return \DOMNodeList */ public function select($selector, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->select($selector, $ctx ? $ctx : $this, $registerNodeNS); } } // fDOMDocumentFragment } fDOMDocument-1.6.6/src/fDOMElement.php000066400000000000000000000343171312543565000174230ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { /** * fDomElement * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * @property fDOMDocument $ownerDocument * */ class fDOMElement extends \DOMElement { /** * @return string */ public function __toString() { return $this->C14N(); } /** * Forward to fDomDocument->query() * * @param string $q XPath to use * @param \DOMNode $ctx \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return \DomNodeList */ public function query($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->query($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->queryOne() * * @param string $q XPath to use * @param \DOMNode $ctx (optional) \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return mixed */ public function queryOne($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->queryOne($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->select() * * @param string $selector A CSS Level 3 Selector string * @param \DOMNode $ctx * @param bool $registerNodeNS * * @return \DOMNodeList */ public function select($selector, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->select($selector, $ctx, $registerNodeNS); } /** * Parse and append XML String to node * * @param String $str string to process * * @return fDomDocumentFragment Reference to the created Fragment */ public function appendXML($str) { $frag = $this->ownerDocument->createDocumentFragment(); $frag->appendXML($str); $this->appendChild($frag); return $frag; } /** * Create a new element and append it * * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextnode Create content as textNode rather then setting nodeValue * * @return fDOMElement Reference to created fDOMElement */ public function appendElement($name, $content = null, $asTextnode = FALSE) { $node = $this->ownerDocument->createElement($name, $content, $asTextnode); $this->appendChild($node); return $node; } /** * Create a new element in given namespace and append it * * @param string $ns Namespace of node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextnode Create content as textNode rather then setting nodeValue * * @return fDOMElement Reference to created fDOMElement */ public function appendElementNS($ns, $name, $content = null, $asTextnode = FALSE) { $node = $this->ownerDocument->createElementNS($ns, $name, $content, $asTextnode); $this->appendChild($node); return $node; } /** * Create a new element in given namespace and append it * * @param string $prefix Namespace prefix for node to create * @param string $name Name of not element to create * @param string $content Optional content to be set * @param bool $asTextnode Create content as textNode rather then setting nodeValue * * @return fDOMElement Reference to created fDOMElement */ public function appendElementPrefix($prefix, $name, $content = null, $asTextnode = FALSE) { $node = $this->ownerDocument->createElementPrefix($prefix, $name, $content, $asTextnode); $this->appendChild($node); return $node; } /** * Create a new text node and append it * * @param string $content Text content to be added * * @return \DOMText */ public function appendTextNode($content) { $text = $this->ownerDocument->createTextNode($content); $this->appendChild($text); return $text; } /** * Create a new fDOMElement * * @see fDOMDocument::createElement * * @param string $name * @param string $content * @param bool $asTextnode * * @return fDOMElement */ public function createElement($name, $content = NULL, $asTextnode = FALSE) { return $this->ownerDocument->createElement($name, $content, $asTextnode); } /** * Create a new fDOMElement in namespace defined by prefix * * @see fDOMDocument::createElementPrefix * * @param string $prefix * @param string $name * @param string $content * @param bool $asTextNode * * @return fDOMElement */ public function createElementPrefix($prefix, $name, $content = NULL, $asTextNode = FALSE) { return $this->ownerDocument->createElementPrefix($prefix, $name, $content, $asTextNode); } /** * Create a new fDOMElement within given namespace and return it * * @param string $namespace Namespace URI for node to create * @param string $name Name of node to create * @param null $content Content to set (optional) * @param bool $asTextNode Create content as textNode rather then setting nodeValue * * @throws fDOMException * * @return fDOMElement */ public function createElementNS($namespace, $name, $content = NULL, $asTextNode = FALSE) { return $this->ownerDocument->createElementNS($namespace, $name, $content, $asTextNode); } /** * Wrapper to DomElement->getAttribute with default value option * * Note: A set but emptry attribute does NOT trigger use of the default * * @param string $attr Attribute to access * @param string $default Default value to use if the attribute is not set * * @return string */ public function getAttribute($attr, $default='') { return $this->hasAttribute($attr) ? parent::getAttribute($attr) : $default; } /** * Wrapper to DomElement->getAttributeNS with default value option * * Note: A set but empty attribute does NOT trigger use of the default * * @param string $ns Namespace of attribute * @param string $attr Attribute to access * @param string $default Default value to use if the attribute is not set * * @return string */ public function getAttributeNS($ns, $attr, $default='') { return $this->hasAttributeNS($ns, $attr) ? parent::getAttributeNS($ns, $attr) : $default; } /** * Wrapper to DOMElement::setAttribute with additional entities support * * @param string $attr Attribute name to set * @param string $value Value to set attribute to * @param bool $keepEntities Flag to signale if entities should be kept * * @throws fDOMException * * @return \DOMAttr * * @see DOMElement::setAttribute() */ public function setAttribute($attr, $value, $keepEntities=false) { if ($keepEntities === true) { $attrNode = $this->ownerDocument->createAttribute($attr); if (!$attrNode) { throw new fDOMException("Setting attribute '$attr' failed.", fDOMException::SetFailedError); } $attrNode->value = $value; $this->appendChild($attrNode); return $attrNode; } return parent::setAttribute($attr, $value); } /** * Wrapper to namespace aware DOMElement::setAttributeNS with additional entities support * * @param string $ns namespace attribute should be in * @param string $attr Attribute name to set * @param string $value Value to set attribute to * @param bool $keepEntities Flag to signale if entities should be kept * * @throws fDOMException * * @return \DOMAttr|null * @see DOMElement::setAttribute() */ public function setAttributeNS($ns, $attr, $value, $keepEntities=false) { if ($keepEntities === true) { $attrNode = $this->ownerDocument->createAttributeNS($ns, $attr); if (!$attrNode) { throw new fDOMException("Setting attribute '$attr' failed.", fDOMException::SetFailedError); } $attrNode->value = $value; $this->appendChild($attrNode); return $attrNode; } return parent::setAttributeNS($ns, $attr, $value); } /** * Helper to add multiple attributes to an element * * @param array $attr Attributes to add as key-value pair * @param bool $keepEntities Flag wether to keep entities * * @return array List with references to created DOMAttr */ public function setAttributes(array $attr, $keepEntities=false) { $attList = array(); foreach($attr as $name => $value) { $attList[] = $this->setAttribute($name, $value, $keepEntities); } return $attList; } /** * Helper to add multiple attributes with the given namespace and prefix * * @param string $ns Namespace of attribute * @param string $prefix Namespace prefix for attribute to create * @param array $attr Attributes to add * @param bool $keepEntities Flag wether to keep entities * * @return void */ public function setAttributesNS($ns, $prefix, array $attr, $keepEntities=false) { foreach($attr as $name => $value) { $this->setAttributeNS($ns, $prefix.':'.$name, $value, $keepEntities); } } /** * Helper method to get children by name * * @param string $tagName tagname to search for * * @return \DOMNodeList */ public function getChildrenByTagName($tagName) { return $this->query("*[local-name()='$tagName']"); } /** * Helper method to get children by name and namespace * * @param string $ns namespace nodes have to be in * @param string $tagName tagname to search for * * @return \DOMNodeList */ public function getChildrenByTagNameNS($ns, $tagName) { return $this->query("*[local-name()='$tagName' and namespace-uri()='$ns']"); } /** * Check if the given node is in the same document * * @param \DomNode $node Node to compare with * * @return boolean true on match, false if they differ * */ public function inSameDocument(\DomNode $node) { return $this->ownerDocument->inSameDocument($node); } /** * Wrapper to DomDocument::saveXML() with current node as context * * @return string */ public function saveXML() { return $this->ownerDocument->saveXML($this); } /** * Wrapper to DomDocument::saveHTML() with current node as context * * @return string */ public function saveHTML() { return $this->ownerDocument->saveHTML($this); } } // fDOMElement } fDOMDocument-1.6.6/src/fDOMException.php000066400000000000000000000132511312543565000177620ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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. * * @package fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license BSD License */ namespace TheSeer\fDOM { /** * fDOMException * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * */ class fDOMException extends \Exception { const LoadError = 1; const ParseError = 2; const SaveError = 3; const QueryError = 4; const RegistrationFailed = 5; const NoDOMXPath = 6; const UnboundPrefix = 7; const SetFailedError = 8; const NameInvalid = 9; /** * List of libxml error objects * * @var array */ private $errorList; /** * Full Error message * * @var string */ private $fullMessage = null; /** * Short Error Message * * @var string */ private $shortMessage = null; private static $fullMesageMode = true; /** * Constructor * * @param string $message Exception message * @param integer $code Exception code * @param \Exception $chain optional chained exception * */ public function __construct($message, $code = 0, \Exception $chain = NULL) { $this->shortMessage = $message; $this->errorList = libxml_get_errors(); libxml_clear_errors(); parent :: __construct($message, $code, $chain); $this->fullMessage = $message."\n\n"; foreach ($this->errorList as $error) { // hack, skip "attempt to load external pseudo error" if ($error->code=='1543') { continue; } if (empty($error->file)) { $this->fullMessage .= '[XML-STRING] '; } else { $this->fullMessage .= '['.$error->file.'] '; } $this->fullMessage .= '[Line: '.$error->line.' - Column: '.$error->column.'] '; switch ($error->level) { case LIBXML_ERR_WARNING: $this->fullMessage .= "Warning $error->code: "; break; case LIBXML_ERR_ERROR: $this->fullMessage .= "Error $error->code: "; break; case LIBXML_ERR_FATAL: $this->fullMessage .= "Fatal Error $error->code: "; break; } $this->fullMessage .= str_replace("\n", '', $error->message)."\n"; if (self::$fullMesageMode) { $this->message = $this->fullMessage; } } } /** * Accessor to fullMessage * * @return string */ public function getFullMessage() { return $this->fullMessage; } /** * Access to shortMessage * * @return string */ public function getShortMessage() { return $this->shortMessage; } /** * Accessor to errorList objets * * @return array */ public function getErrorList() { return $this->errorList; } /** * Toggle wehter getMessage() should return full or only exception message * * @param boolean $full Flag to enable or disable full message output * * @return void */ public function toggleFullMessage($full = true) { $this->message = $full ? $this->fullMessage : $this->shortMessage; } /** * Magic method for string context * * @return string */ public function __toString() { return $this->fullMessage; } } // fDOMException } fDOMDocument-1.6.6/src/fDOMNode.php000066400000000000000000000143321312543565000167120ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { /** * fDomNode * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * @property fDOMDocument $ownerDocument * */ class fDOMNode extends \DOMNode { /** * @return string */ public function __toString() { return $this->C14N(); } /** * Create a new fDOMElement * * @see fDOMDocument::createElement * * @param string $name * @param string $content * @param bool $asTextnode * * @return fDOMElement */ public function createElement($name, $content = NULL, $asTextnode = FALSE) { return $this->ownerDocument->createElement($name, $content, $asTextnode); } /** * Create a new fDOMElement in namespace defined by prefix * * @see fDOMDocument::createElementPrefix * * @param string $prefix * @param string $name * @param string $content * @param bool $asTextNode * * @return fDOMElement */ public function createElementPrefix($prefix, $name, $content = NULL, $asTextNode = FALSE) { return $this->ownerDocument->createElementPrefix($prefix, $name, $content, $asTextNode); } /** * Create a new fDOMElement within given namespace and return it * * @param string $namespace Namespace URI for node to create * @param string $name Name of node to create * @param null $content Content to set (optional) * @param bool $asTextNode Create content as textNode rather then setting nodeValue * * @throws fDOMException * * @return fDOMElement */ public function createElementNS($namespace, $name, $content = NULL, $asTextNode = FALSE) { return $this->ownerDocument->createElementNS($namespace, $name, $content, $asTextNode); } /** * Forward to fDomDocument->query() * * @param string $q XPath to use * @param \DOMNode $ctx \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return \DomNodeList */ public function query($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->query($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->queryOne() * * @param string $q XPath to use * @param \DOMNode $ctx (optional) \DOMNode to overwrite context * @param boolean $registerNodeNS Register flag pass thru * * @return mixed */ public function queryOne($q, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->queryOne($q, $ctx ? $ctx : $this, $registerNodeNS); } /** * Forward to fDomDocument->select() * * @param string $selector A CSS Level 3 Selector string * @param \DOMNode $ctx * @param bool $registerNodeNS * * @return \DOMNodeList */ public function select($selector, \DOMNode $ctx = null, $registerNodeNS = true) { return $this->ownerDocument->select($selector, $ctx, $registerNodeNS); } /** * Check if the given node is in the same document * * @param \DomNode $node Node to compare with * * @return boolean true on match, false if they differ * */ public function inSameDocument(\DOMNode $node) { return $this->ownerDocument->inSameDocument($node); } /** * Wrapper to DomDocument::saveXML() with current node as context * * @return string */ public function saveXML() { return $this->ownerDocument->saveXML($this); } /** * Wrapper to DomDocument::saveHTML() with current node as context * * @return string */ public function saveHTML() { return $this->ownerDocument->saveHTML($this); } } // fDOMNode } fDOMDocument-1.6.6/src/fDOMXPath.php000066400000000000000000000127411312543565000170530ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM { /** * fDOMXPath extension to PHP's DOMXPath. * * @category PHP * @package TheSeer\fDOM * @author Arne Blankerts * @access public * */ class fDOMXPath extends \DOMXPath { /** * @var \DOMDocument */ protected $doc; /** * @param \DOMDocument $doc */ public function __construct(\DOMDocument $doc) { parent::__construct($doc); $this->doc = $doc; } /** * @param string $xpath * @param array $valueMap * * @return string */ public function prepare($xpath, array $valueMap) { if (count($valueMap)==0) { return $xpath; } foreach($valueMap as $key => $value) { $xpath = str_replace(':'.$key, $this->quote($value), $xpath); } return $xpath; } /** * @param string $q * @param \DOMNode $ctx * @param bool $registerNodeNS * * @throws fDOMException * * @return \DOMNodeList */ public function query($q, \DOMNode $ctx = null, $registerNodeNS = true) { libxml_clear_errors(); if (version_compare(PHP_VERSION, '5.3.3', '<') || strpos(PHP_VERSION, 'hiphop') || strpos(PHP_VERSION, 'hhvm')) { $rc = parent::query($q, ($ctx instanceof \DOMNode) ? $ctx : $this->doc->documentElement); } else { $rc = parent::query($q, ($ctx instanceof \DOMNode) ? $ctx : $this->doc->documentElement, $registerNodeNS); } if (libxml_get_last_error()) { throw new fDOMException('evaluating xpath expression failed.', fDOMException::QueryError); } return $rc; } /** * @param string $q * @param \DOMNode $ctx * @param bool $registerNodeNS * * @throws fDOMException * * @return mixed */ public function evaluate($q, \DOMNode $ctx = null, $registerNodeNS = true) { libxml_clear_errors(); if (version_compare(PHP_VERSION, '5.3.3', '<') || strpos(PHP_VERSION, 'hiphop') || strpos(PHP_VERSION, 'hhvm')) { $rc = parent::evaluate($q, ($ctx instanceof \DOMNode) ? $ctx : $this->doc->documentElement); } else { $rc = parent::evaluate($q, ($ctx instanceof \DOMNode) ? $ctx : $this->doc->documentElement, $registerNodeNS); } if (libxml_get_last_error()) { throw new fDOMException('evaluating xpath expression failed.', fDOMException::QueryError); } return $rc; } /** * @param string $q * @param \DOMNode $ctx * @param bool $registerNodeNS * * @throws fDOMException * * @return \DOMNode|mixed */ public function queryOne($q, \DOMNode $ctx = null, $registerNodeNS = true) { $rc = $this->evaluate($q, $ctx, $registerNodeNS); if ($rc instanceof \DOMNodelist) { return $rc->item(0); } return $rc; } /** * @param string $str * * @return string */ public function quote($str) { if (strpos($str, '"') === false) { return '"'.$str.'"'; } $parts = explode('"', $str); return 'concat("' . join('",\'"\',"', $parts).'")'; } } } fDOMDocument-1.6.6/tests/000077500000000000000000000000001312543565000151565ustar00rootroot00000000000000fDOMDocument-1.6.6/tests/Translator.test.php000066400000000000000000000076541312543565000210120ustar00rootroot00000000000000assertEquals($xpath, $translator->translate($selector)); } public function provider() { return array( array("div", '//div'), array("body div", '//body//div'), array("div p", '//div//p'), array("div > p", '//div/p'), array("div + p", '//div/following-sibling::*[1]/self::p'), array("div ~ p", '//div/following-sibling::p'), array("div[class^=exa][class$=mple]", '//div[starts-with(@class,"exa") and (substring(@class,string-length(@class)-3)=class)]'), array("div p a", '//div//p//a'), array("div, p, a", '//div|//p|//a'), array(".note", '//*[contains(concat(" ",normalize-space(@class)," ")," note ")]'), array("div.example", '//div[contains(concat(" ",normalize-space(@class)," ")," example ")]'), array("ul .tocline2", '//ul//*[contains(concat(" ",normalize-space(@class)," ")," tocline2 ")]'), array("div.example, div.note", '//div[contains(concat(" ",normalize-space(@class)," ")," example ")]|//div[contains(concat(" ",normalize-space(@class)," ")," note ")]'), array("#title", '//*[@id="title"]'), array("h1#title", '//h1[@id="title"]'), array("div #title", '//div//*[@id="title"]'), array("ul.toc li.tocline2", '//ul[contains(concat(" ",normalize-space(@class)," ")," toc ")]//li[contains(concat(" ",normalize-space(@class)," ")," tocline2 ")]'), array("ul.toc > li.tocline2", '//ul[contains(concat(" ",normalize-space(@class)," ")," toc ")]/li[contains(concat(" ",normalize-space(@class)," ")," tocline2 ")]'), array("h1#title + div > p", '//h1[@id="title"]/following-sibling::*[1]/self::div/p'), array("h1[id]:contains(Selectors)", '//h1[@id and (contains(string(.),"Selectors"))]'), array("a[href][lang][class]", '//a[@href and (@lang) and (@class)]'), array("div[class]", '//div[@class]'), array("div[class=example]", '//div[@class="example"]'), array("div[class^=exa]", '//div[starts-with(@class,"exa")]'), array("div[class$=mple]", '//div[substring(@class,string-length(@class)-3)=class]'), array("div[class*=e]", '//div[contains(@class,"e")]'), array("div[class|=dialog]", '//div[@class="dialog" or starts-with(@class,concat("dialog","-"))]'), array("div[class!=made_up]", '//div[not(@class) or @class!="made_up"]'), array("div[class~=example]", '//div[contains(concat(" ",normalize-space(@class)," "),concat(" ","example"," "))]'), array("div:not(.example)", '//div[not(contains(concat(" ",normalize-space(@class)," ")," example "))]'), array("p:contains(selectors)", '//p[contains(string(.),"selectors")]'), array("p:nth-child(even)", '//*[position() mod 2=0 and position()>=0]/self::p'), array("p:nth-child(2n)", '//*[(position()-) mod 2=0 and position()>=]/self::p'), array("p:nth-child(odd)", '//p[(count(preceding-sibling::*) + 1) mod 2=1]'), array("p:nth-child(2n+1)", '//*[(position()-1) mod 2=0 and position()>=1]/self::p'), array("p:nth-child(n)", '//p'), array("p:only-child", '//*[last()=1]/self::p'), array("p:last-child", '//p[not(following-sibling::*)]'), array("p:first-child", '//*[1]/self::p'), array("foo|bar", '//foo:bar') ); } } } fDOMDocument-1.6.6/tests/XPathQuery.test.php000066400000000000000000000114141312543565000207200ustar00rootroot00000000000000 * 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. * * * Neither the name of Arne Blankerts nor the names of contributors * may 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 HOLDER ORCONTRIBUTORS * 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 PHP * @package TheSeer\fDOM * @author Arne Blankerts * @copyright Arne Blankerts , All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://github.com/theseer/fdomdocument * */ namespace TheSeer\fDOM\Tests { use TheSeer\fDOM\XPathQuery; use TheSeer\fDOM\fDOMDocument; class XPathQueryTest extends \PHPUnit\Framework\TestCase { private $dom; protected function setUp() { $this->dom = new fDOMDocument(); $this->dom->loadXML(''); } public function testFindingKeysInQueryWorks() { $xp = new XPathQuery(':key'); $this->assertEquals(array('key'), $xp->getKeys()); } /** * @expectedException TheSeer\fDOM\XPathQueryException */ public function testTryingToBindNonExistingKeyThrowsException() { $xp = new XPathQuery(':key'); $xp->bind('other', 123); } public function testBoundValueForKeyGetsApplied() { $xp = new XPathQuery(':key'); $xp->bind('key', 123); $this->assertEquals('"123"', $xp->generate($this->dom)); } public function testAppliedValueForKeyIsUsedOnQueryAndReturnsNode() { $xp = new XPathQuery('//*[@attr = :key]'); $xp->bind('key', 'value'); $res = $xp->query($this->dom); $this->assertInstanceOf('\DOMNodelist', $res); $this->assertEquals(1, $res->length); $this->assertInstanceOf('\DOMNode', $res->item(0)); } public function testOverwriteValueOnQuery() { $xp = new XPathQuery('//*[@attr = :key]'); $xp->bind('key', 'first'); $res = $xp->query($this->dom, array('key' => 'value')); $this->assertEquals(1, $res->length); $this->assertInstanceOf('\DOMNode', $res->item(0)); } public function testAppliedValueForKeyIsUsedOnEvaluateAndReturnsNode() { $xp = new XPathQuery('//*[@attr = :key]'); $xp->bind('key', 'value'); $res = $xp->evaluate($this->dom); $this->assertInstanceOf('\DOMNodelist', $res); $this->assertEquals(1, $res->length); $this->assertInstanceOf('\DOMNode', $res->item(0)); } public function testOverwriteValueOnEvaluate() { $xp = new XPathQuery('//*[@attr = :key]'); $xp->bind('key', 'first'); $res = $xp->evaluate($this->dom, array('key' => 'value')); $this->assertEquals(1, $res->length); $this->assertInstanceOf('\DOMNode', $res->item(0)); } public function testCallToQueryOneReturnsOneNode() { $xp = new XPathQuery('//*[@attr]'); $res = $xp->queryOne($this->dom); $this->assertInstanceOf('\DOMNode', $res); } public function testQueryCanBeRunWithStandardDomDocument() { $xp = new XPathQuery('/'); $res = $xp->query(new \DomDocument()); $this->assertInstanceOf('\DOMNodelist', $res); } } } fDOMDocument-1.6.6/tests/_data/000077500000000000000000000000001312543565000162265ustar00rootroot00000000000000fDOMDocument-1.6.6/tests/_data/broken.xml000066400000000000000000000001331312543565000202250ustar00rootroot00000000000000