Add the Chronological
This commit is contained in:
27
vendor/sabre/xml/LICENSE
vendored
Normal file
27
vendor/sabre/xml/LICENSE
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/)
|
||||
|
||||
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 Sabre nor the names of its 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 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.
|
||||
26
vendor/sabre/xml/README.md
vendored
Normal file
26
vendor/sabre/xml/README.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
sabre/xml
|
||||
=========
|
||||
|
||||

|
||||
|
||||
The sabre/xml library is a specialized XML reader and writer.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* [Introduction](http://sabre.io/xml/).
|
||||
* [Installation](http://sabre.io/xml/install/).
|
||||
* [Reading XML](http://sabre.io/xml/reading/).
|
||||
* [Writing XML](http://sabre.io/xml/writing/).
|
||||
|
||||
Major version 3 implements type declarations for input parameters, function returns, variables etc. It supports PHP 7.4 and PHP 8. When you upgrade to major version 3, if you extend classes etc., then you will need to make similar type declarations in your code.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
Head over to the [SabreDAV mailing list](http://groups.google.com/group/sabredav-discuss) for any questions.
|
||||
|
||||
Made at fruux
|
||||
-------------
|
||||
|
||||
This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.
|
||||
70
vendor/sabre/xml/composer.json
vendored
Normal file
70
vendor/sabre/xml/composer.json
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
"description" : "sabre/xml is an XML library that you may not hate.",
|
||||
"keywords" : [ "XML", "XMLReader", "XMLWriter", "DOM" ],
|
||||
"homepage" : "https://sabre.io/xml/",
|
||||
"license" : "BSD-3-Clause",
|
||||
"require" : {
|
||||
"php" : "^7.4 || ^8.0",
|
||||
"ext-xmlwriter" : "*",
|
||||
"ext-xmlreader" : "*",
|
||||
"ext-dom" : "*",
|
||||
"lib-libxml" : ">=2.6.20",
|
||||
"sabre/uri" : ">=2.0,<4.0.0"
|
||||
},
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "Evert Pot",
|
||||
"email" : "me@evertpot.com",
|
||||
"homepage" : "http://evertpot.com/",
|
||||
"role" : "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Markus Staab",
|
||||
"email": "markus.staab@redaxo.de",
|
||||
"role" : "Developer"
|
||||
}
|
||||
],
|
||||
"support" : {
|
||||
"forum" : "https://groups.google.com/group/sabredav-discuss",
|
||||
"source" : "https://github.com/fruux/sabre-xml"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4" : {
|
||||
"Sabre\\Xml\\" : "lib/"
|
||||
},
|
||||
"files": [
|
||||
"lib/Deserializer/functions.php",
|
||||
"lib/Serializer/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev" : {
|
||||
"psr-4" : {
|
||||
"Sabre\\Xml\\" : "tests/Sabre/Xml/"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.64",
|
||||
"phpstan/phpstan": "^1.12",
|
||||
"phpunit/phpunit" : "^9.6"
|
||||
},
|
||||
"scripts": {
|
||||
"phpstan": [
|
||||
"phpstan analyse"
|
||||
],
|
||||
"phpstan-baseline": [
|
||||
"phpstan analyse --generate-baseline phpstan-baseline.neon"
|
||||
],
|
||||
"cs-fixer": [
|
||||
"PHP_CS_FIXER_IGNORE_ENV=true php-cs-fixer fix"
|
||||
],
|
||||
"phpunit": [
|
||||
"phpunit --configuration tests/phpunit.xml"
|
||||
],
|
||||
"test": [
|
||||
"composer phpstan",
|
||||
"composer cs-fixer",
|
||||
"composer phpunit"
|
||||
]
|
||||
}
|
||||
}
|
||||
116
vendor/sabre/xml/lib/ContextStackTrait.php
vendored
Normal file
116
vendor/sabre/xml/lib/ContextStackTrait.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* Context Stack.
|
||||
*
|
||||
* The Context maintains information about a document during either reading or
|
||||
* writing.
|
||||
*
|
||||
* During this process, it may be necessary to override this context
|
||||
* information.
|
||||
*
|
||||
* This trait allows easy access to the context, and allows the end-user to
|
||||
* override its settings for document fragments, and easily restore it again
|
||||
* later.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
trait ContextStackTrait
|
||||
{
|
||||
/**
|
||||
* This is the element map. It contains a list of XML elements (in clark
|
||||
* notation) as keys and PHP class names as values.
|
||||
*
|
||||
* The PHP class names must implement Sabre\Xml\Element.
|
||||
*
|
||||
* Values may also be a callable. In that case the function will be called
|
||||
* directly.
|
||||
*
|
||||
* @phpstan-var array<string, class-string|callable|object>
|
||||
*/
|
||||
public array $elementMap = [];
|
||||
|
||||
/**
|
||||
* A contextUri pointing to the document being parsed / written.
|
||||
* This uri may be used to resolve relative urls that may appear in the
|
||||
* document.
|
||||
*
|
||||
* The reader and writer don't use this property, but as it's an extremely
|
||||
* common use-case for parsing XML documents, it's added here as a
|
||||
* convenience.
|
||||
*/
|
||||
public ?string $contextUri = null;
|
||||
|
||||
/**
|
||||
* This is a list of namespaces that you want to give default prefixes.
|
||||
*
|
||||
* You must make sure you create this entire list before starting to write.
|
||||
* They should be registered on the root element.
|
||||
*
|
||||
* @phpstan-var array<string, class-string|string|null>
|
||||
*/
|
||||
public array $namespaceMap = [];
|
||||
|
||||
/**
|
||||
* This is a list of custom serializers for specific classes.
|
||||
*
|
||||
* The writer may use this if you attempt to serialize an object with a
|
||||
* class that does not implement XmlSerializable.
|
||||
*
|
||||
* Instead, it will look at this classmap to see if there is a custom
|
||||
* serializer here. This is useful if you don't want your value objects
|
||||
* to be responsible for serializing themselves.
|
||||
*
|
||||
* The keys in this classmap need to be fully qualified PHP class names,
|
||||
* the values must be callbacks. The callbacks take two arguments. The
|
||||
* writer class, and the value that must be written.
|
||||
*
|
||||
* function (Writer $writer, object $value)
|
||||
*
|
||||
* @phpstan-var array<class-string, callable(Writer, object):mixed>
|
||||
*/
|
||||
public array $classMap = [];
|
||||
|
||||
/**
|
||||
* Backups of previous contexts.
|
||||
*
|
||||
* @var list<mixed>
|
||||
*/
|
||||
protected array $contextStack = [];
|
||||
|
||||
/**
|
||||
* Create a new "context".
|
||||
*
|
||||
* This allows you to safely modify the elementMap, contextUri or
|
||||
* namespaceMap. After you're done, you can restore the old data again
|
||||
* with popContext.
|
||||
*/
|
||||
public function pushContext(): void
|
||||
{
|
||||
$this->contextStack[] = [
|
||||
$this->elementMap,
|
||||
$this->contextUri,
|
||||
$this->namespaceMap,
|
||||
$this->classMap,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the previous "context".
|
||||
*/
|
||||
public function popContext(): void
|
||||
{
|
||||
list(
|
||||
$this->elementMap,
|
||||
$this->contextUri,
|
||||
$this->namespaceMap,
|
||||
$this->classMap,
|
||||
) = array_pop($this->contextStack);
|
||||
}
|
||||
}
|
||||
388
vendor/sabre/xml/lib/Deserializer/functions.php
vendored
Normal file
388
vendor/sabre/xml/lib/Deserializer/functions.php
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Deserializer;
|
||||
|
||||
use Sabre\Xml\Reader;
|
||||
|
||||
/**
|
||||
* This class provides a number of 'deserializer' helper functions.
|
||||
* These can be used to easily specify custom deserializers for specific
|
||||
* XML elements.
|
||||
*
|
||||
* You can either use these functions from within the $elementMap in the
|
||||
* Service or Reader class, or you can call them from within your own
|
||||
* deserializer functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The 'keyValue' deserializer parses all child elements, and outputs them as
|
||||
* a "key=>value" array.
|
||||
*
|
||||
* For example, keyvalue will parse:
|
||||
*
|
||||
* <?xml version="1.0"?>
|
||||
* <s:root xmlns:s="http://sabredav.org/ns">
|
||||
* <s:elem1>value1</s:elem1>
|
||||
* <s:elem2>value2</s:elem2>
|
||||
* <s:elem3 />
|
||||
* </s:root>
|
||||
*
|
||||
* Into:
|
||||
*
|
||||
* [
|
||||
* "{http://sabredav.org/ns}elem1" => "value1",
|
||||
* "{http://sabredav.org/ns}elem2" => "value2",
|
||||
* "{http://sabredav.org/ns}elem3" => null,
|
||||
* ];
|
||||
*
|
||||
* If you specify the 'namespace' argument, the deserializer will remove
|
||||
* the namespaces of the keys that match that namespace.
|
||||
*
|
||||
* For example, if you call keyValue like this:
|
||||
*
|
||||
* keyValue($reader, 'http://sabredav.org/ns')
|
||||
*
|
||||
* it's output will instead be:
|
||||
*
|
||||
* [
|
||||
* "elem1" => "value1",
|
||||
* "elem2" => "value2",
|
||||
* "elem3" => null,
|
||||
* ];
|
||||
*
|
||||
* Attributes will be removed from the top-level elements. If elements with
|
||||
* the same name appear twice in the list, only the last one will be kept.
|
||||
*
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
function keyValue(Reader $reader, ?string $namespace = null): array
|
||||
{
|
||||
// If there's no children, we don't do anything.
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$reader->read()) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (Reader::END_ELEMENT === $reader->nodeType) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$values = [];
|
||||
|
||||
do {
|
||||
if (Reader::ELEMENT === $reader->nodeType) {
|
||||
if (null !== $namespace && $reader->namespaceURI === $namespace) {
|
||||
$values[$reader->localName] = $reader->parseCurrentElement()['value'];
|
||||
} else {
|
||||
$clark = $reader->getClark();
|
||||
$values[$clark] = $reader->parseCurrentElement()['value'];
|
||||
}
|
||||
} else {
|
||||
if (!$reader->read()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (Reader::END_ELEMENT !== $reader->nodeType);
|
||||
|
||||
$reader->read();
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* The 'enum' deserializer parses elements into a simple list
|
||||
* without values or attributes.
|
||||
*
|
||||
* For example, Elements will parse:
|
||||
*
|
||||
* <?xml version="1.0"? >
|
||||
* <s:root xmlns:s="http://sabredav.org/ns">
|
||||
* <s:elem1 />
|
||||
* <s:elem2 />
|
||||
* <s:elem3 />
|
||||
* <s:elem4>content</s:elem4>
|
||||
* <s:elem5 attr="val" />
|
||||
* </s:root>
|
||||
*
|
||||
* Into:
|
||||
*
|
||||
* [
|
||||
* "{http://sabredav.org/ns}elem1",
|
||||
* "{http://sabredav.org/ns}elem2",
|
||||
* "{http://sabredav.org/ns}elem3",
|
||||
* "{http://sabredav.org/ns}elem4",
|
||||
* "{http://sabredav.org/ns}elem5",
|
||||
* ];
|
||||
*
|
||||
* This is useful for 'enum'-like structures.
|
||||
*
|
||||
* If the $namespace argument is specified, it will strip the namespace
|
||||
* for all elements that match that.
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* enum($reader, 'http://sabredav.org/ns')
|
||||
*
|
||||
* would return:
|
||||
*
|
||||
* [
|
||||
* "elem1",
|
||||
* "elem2",
|
||||
* "elem3",
|
||||
* "elem4",
|
||||
* "elem5",
|
||||
* ];
|
||||
*
|
||||
* @return string[]
|
||||
*
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
function enum(Reader $reader, ?string $namespace = null): array
|
||||
{
|
||||
// If there's no children, we don't do anything.
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
if (!$reader->read()) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (Reader::END_ELEMENT === $reader->nodeType) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
$currentDepth = $reader->depth;
|
||||
|
||||
$values = [];
|
||||
do {
|
||||
if (Reader::ELEMENT !== $reader->nodeType) {
|
||||
continue;
|
||||
}
|
||||
if (!is_null($namespace) && $namespace === $reader->namespaceURI) {
|
||||
$values[] = $reader->localName;
|
||||
} else {
|
||||
$values[] = (string) $reader->getClark();
|
||||
}
|
||||
} while ($reader->depth >= $currentDepth && $reader->next());
|
||||
|
||||
$reader->next();
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* The valueObject deserializer turns an XML element into a PHP object of
|
||||
* a specific class.
|
||||
*
|
||||
* This is primarily used by the mapValueObject function from the Service
|
||||
* class, but it can also easily be used for more specific situations.
|
||||
*
|
||||
* @template C of object
|
||||
*
|
||||
* @param class-string<C> $className
|
||||
*
|
||||
* @phpstan-return C
|
||||
*/
|
||||
function valueObject(Reader $reader, string $className, string $namespace): object
|
||||
{
|
||||
$valueObject = new $className();
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
|
||||
return $valueObject;
|
||||
}
|
||||
|
||||
$defaultProperties = get_class_vars($className);
|
||||
|
||||
$reader->read();
|
||||
do {
|
||||
if (Reader::ELEMENT === $reader->nodeType && $reader->namespaceURI == $namespace) {
|
||||
if (property_exists($valueObject, $reader->localName)) {
|
||||
if (is_array($defaultProperties[$reader->localName])) {
|
||||
$valueObject->{$reader->localName}[] = $reader->parseCurrentElement()['value'];
|
||||
} else {
|
||||
$valueObject->{$reader->localName} = $reader->parseCurrentElement()['value'];
|
||||
}
|
||||
} else {
|
||||
// Ignore property
|
||||
$reader->next();
|
||||
}
|
||||
} elseif (Reader::ELEMENT === $reader->nodeType) {
|
||||
// Skipping element from different namespace
|
||||
$reader->next();
|
||||
} else {
|
||||
if (Reader::END_ELEMENT !== $reader->nodeType && !$reader->read()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (Reader::END_ELEMENT !== $reader->nodeType);
|
||||
|
||||
$reader->read();
|
||||
|
||||
return $valueObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* This deserializer helps you deserialize xml structures that look like
|
||||
* this:.
|
||||
*
|
||||
* <collection>
|
||||
* <item>...</item>
|
||||
* <item>...</item>
|
||||
* <item>...</item>
|
||||
* </collection>
|
||||
*
|
||||
* Many XML documents use patterns like that, and this deserializer
|
||||
* allow you to get all the 'items' as an array.
|
||||
*
|
||||
* In that previous example, you would register the deserializer as such:
|
||||
*
|
||||
* $reader->elementMap['{}collection'] = function($reader) {
|
||||
* return repeatingElements($reader, '{}item');
|
||||
* }
|
||||
*
|
||||
* The repeatingElements deserializer simply returns everything as an array.
|
||||
*
|
||||
* $childElementName must either be a clark-notation element name, or if no
|
||||
* namespace is used, the bare element name.
|
||||
*
|
||||
* @phpstan-return list<mixed>
|
||||
*/
|
||||
function repeatingElements(Reader $reader, string $childElementName): array
|
||||
{
|
||||
if ('{' !== $childElementName[0]) {
|
||||
$childElementName = '{}'.$childElementName;
|
||||
}
|
||||
$result = [];
|
||||
|
||||
foreach ($reader->parseGetElements() as $element) {
|
||||
if ($element['name'] === $childElementName) {
|
||||
$result[] = $element['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This deserializer helps you to deserialize structures which contain mixed content.
|
||||
*
|
||||
* <p>some text <extref>and an inline tag</extref>and even more text</p>
|
||||
*
|
||||
* The above example will return
|
||||
*
|
||||
* [
|
||||
* 'some text',
|
||||
* [
|
||||
* 'name' => '{}extref',
|
||||
* 'value' => 'and an inline tag',
|
||||
* 'attributes' => []
|
||||
* ],
|
||||
* 'and even more text'
|
||||
* ]
|
||||
*
|
||||
* In strict XML documents you won't find this kind of markup but in html this is a quite common pattern.
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
function mixedContent(Reader $reader): array
|
||||
{
|
||||
// If there's no children, we don't do anything.
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$previousDepth = $reader->depth;
|
||||
|
||||
$content = [];
|
||||
$reader->read();
|
||||
while (true) {
|
||||
if (Reader::ELEMENT == $reader->nodeType) {
|
||||
$content[] = $reader->parseCurrentElement();
|
||||
} elseif ($reader->depth >= $previousDepth && in_array($reader->nodeType, [Reader::TEXT, Reader::CDATA, Reader::WHITESPACE])) {
|
||||
$content[] = $reader->value;
|
||||
$reader->read();
|
||||
} elseif (Reader::END_ELEMENT == $reader->nodeType) {
|
||||
// Ensuring we are moving the cursor after the end element.
|
||||
$reader->read();
|
||||
break;
|
||||
} else {
|
||||
$reader->read();
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* The functionCaller deserializer turns an XML element into whatever your callable returns.
|
||||
*
|
||||
* You can use, e.g., a named constructor (factory method) to create an object using
|
||||
* this function.
|
||||
*
|
||||
* @return mixed whatever the 'func' callable returns
|
||||
*
|
||||
* @throws \InvalidArgumentException|\ReflectionException
|
||||
*/
|
||||
function functionCaller(Reader $reader, callable $func, string $namespace)
|
||||
{
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$funcArgs = [];
|
||||
if (is_array($func)) {
|
||||
$ref = new \ReflectionMethod($func[0], $func[1]);
|
||||
} elseif (is_string($func) && false !== strpos($func, '::')) {
|
||||
// We have a string that should refer to a method that exists, like "MyClass::someMethod"
|
||||
// ReflectionMethod knows how to handle that as-is
|
||||
$ref = new \ReflectionMethod($func);
|
||||
} elseif ($func instanceof \Closure || is_string($func)) {
|
||||
// We have an actual Closure (a real function) or a string that is the name of a function
|
||||
// ReflectionFunction can take either of those
|
||||
$ref = new \ReflectionFunction($func);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(__METHOD__.' unable to use func parameter with ReflectionMethod or ReflectionFunction.');
|
||||
}
|
||||
|
||||
foreach ($ref->getParameters() as $parameter) {
|
||||
$funcArgs[$parameter->getName()] = null;
|
||||
}
|
||||
|
||||
$reader->read();
|
||||
do {
|
||||
if (Reader::ELEMENT === $reader->nodeType && $reader->namespaceURI == $namespace) {
|
||||
if (array_key_exists($reader->localName, $funcArgs)) {
|
||||
$funcArgs[$reader->localName] = $reader->parseCurrentElement()['value'];
|
||||
} else {
|
||||
// Ignore property
|
||||
$reader->next();
|
||||
}
|
||||
} else {
|
||||
$reader->read();
|
||||
}
|
||||
} while (Reader::END_ELEMENT !== $reader->nodeType);
|
||||
$reader->read();
|
||||
|
||||
return $func(...array_values($funcArgs));
|
||||
}
|
||||
22
vendor/sabre/xml/lib/Element.php
vendored
Normal file
22
vendor/sabre/xml/lib/Element.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* This is the XML element interface.
|
||||
*
|
||||
* Elements are responsible for serializing and deserializing part of an XML
|
||||
* document into PHP values.
|
||||
*
|
||||
* It combines XmlSerializable and XmlDeserializable into one logical class
|
||||
* that does both.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
interface Element extends XmlSerializable, XmlDeserializable
|
||||
{
|
||||
}
|
||||
84
vendor/sabre/xml/lib/Element/Base.php
vendored
Normal file
84
vendor/sabre/xml/lib/Element/Base.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml;
|
||||
|
||||
/**
|
||||
* The Base XML element is the standard parser & generator that's used by the
|
||||
* XML reader and writer.
|
||||
*
|
||||
* It spits out a simple PHP array structure during deserialization, that can
|
||||
* also be directly injected back into Writer::write.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Base implements Xml\Element
|
||||
{
|
||||
/**
|
||||
* @var mixed PHP value to serialize
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mixed $value PHP value to serialize
|
||||
*/
|
||||
public function __construct($value = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
$writer->write($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* Important note 2: You are responsible for advancing the reader to the
|
||||
* next element. Not doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @return array<int,array<string, mixed>>|string|null
|
||||
*/
|
||||
public static function xmlDeserialize(Xml\Reader $reader)
|
||||
{
|
||||
$subTree = $reader->parseInnerTree();
|
||||
|
||||
return $subTree;
|
||||
}
|
||||
}
|
||||
57
vendor/sabre/xml/lib/Element/Cdata.php
vendored
Normal file
57
vendor/sabre/xml/lib/Element/Cdata.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml;
|
||||
|
||||
/**
|
||||
* CDATA element.
|
||||
*
|
||||
* This element allows you to easily inject CDATA.
|
||||
*
|
||||
* Note that we strongly recommend avoiding CDATA nodes, unless you definitely
|
||||
* know what you're doing, or you're working with unchangeable systems that
|
||||
* require CDATA.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Cdata implements Xml\XmlSerializable
|
||||
{
|
||||
/**
|
||||
* CDATA element value.
|
||||
*/
|
||||
protected string $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
$writer->writeCData($this->value);
|
||||
}
|
||||
}
|
||||
102
vendor/sabre/xml/lib/Element/Elements.php
vendored
Normal file
102
vendor/sabre/xml/lib/Element/Elements.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml;
|
||||
use Sabre\Xml\Deserializer;
|
||||
use Sabre\Xml\Serializer;
|
||||
|
||||
/**
|
||||
* 'Elements' is a simple list of elements, without values or attributes.
|
||||
* For example, Elements will parse:.
|
||||
*
|
||||
* <?xml version="1.0"?>
|
||||
* <s:root xmlns:s="http://sabredav.org/ns">
|
||||
* <s:elem1 />
|
||||
* <s:elem2 />
|
||||
* <s:elem3 />
|
||||
* <s:elem4>content</s:elem4>
|
||||
* <s:elem5 attr="val" />
|
||||
* </s:root>
|
||||
*
|
||||
* Into:
|
||||
*
|
||||
* [
|
||||
* "{http://sabredav.org/ns}elem1",
|
||||
* "{http://sabredav.org/ns}elem2",
|
||||
* "{http://sabredav.org/ns}elem3",
|
||||
* "{http://sabredav.org/ns}elem4",
|
||||
* "{http://sabredav.org/ns}elem5",
|
||||
* ];
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Elements implements Xml\Element
|
||||
{
|
||||
/**
|
||||
* Value to serialize.
|
||||
*
|
||||
* @var array<int, mixed>
|
||||
*/
|
||||
protected array $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array<int, mixed> $value
|
||||
*/
|
||||
public function __construct(array $value = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
Serializer\enum($writer, $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* Important note 2: You are responsible for advancing the reader to the
|
||||
* next element. Not doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseSubTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function xmlDeserialize(Xml\Reader $reader)
|
||||
{
|
||||
return Deserializer\enum($reader);
|
||||
}
|
||||
}
|
||||
102
vendor/sabre/xml/lib/Element/KeyValue.php
vendored
Normal file
102
vendor/sabre/xml/lib/Element/KeyValue.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml;
|
||||
use Sabre\Xml\Deserializer;
|
||||
|
||||
/**
|
||||
* 'KeyValue' parses out all child elements from a single node, and outputs a
|
||||
* key=>value struct.
|
||||
*
|
||||
* Attributes will be removed, and duplicate child elements are discarded.
|
||||
* Complex values within the elements will be parsed by the 'standard' parser.
|
||||
*
|
||||
* For example, KeyValue will parse:
|
||||
*
|
||||
* <?xml version="1.0"?>
|
||||
* <s:root xmlns:s="http://sabredav.org/ns">
|
||||
* <s:elem1>value1</s:elem1>
|
||||
* <s:elem2>value2</s:elem2>
|
||||
* <s:elem3 />
|
||||
* </s:root>
|
||||
*
|
||||
* Into:
|
||||
*
|
||||
* [
|
||||
* "{http://sabredav.org/ns}elem1" => "value1",
|
||||
* "{http://sabredav.org/ns}elem2" => "value2",
|
||||
* "{http://sabredav.org/ns}elem3" => null,
|
||||
* ];
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class KeyValue implements Xml\Element
|
||||
{
|
||||
/**
|
||||
* Value to serialize.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array<string, mixed> $value
|
||||
*/
|
||||
public function __construct(array $value = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
$writer->write($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* Important note 2: You are responsible for advancing the reader to the
|
||||
* next element. Not doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function xmlDeserialize(Xml\Reader $reader)
|
||||
{
|
||||
return Deserializer\keyValue($reader);
|
||||
}
|
||||
}
|
||||
95
vendor/sabre/xml/lib/Element/Uri.php
vendored
Normal file
95
vendor/sabre/xml/lib/Element/Uri.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml;
|
||||
|
||||
use function Sabre\Uri\resolve;
|
||||
|
||||
/**
|
||||
* Uri element.
|
||||
*
|
||||
* This represents a single uri. An example of how this may be encoded:
|
||||
*
|
||||
* <link>/foo/bar</link>
|
||||
* <d:href xmlns:d="DAV:">http://example.org/hi</d:href>
|
||||
*
|
||||
* If the uri is relative, it will be automatically expanded to an absolute
|
||||
* url during writing and reading, if the contextUri property is set on the
|
||||
* reader and/or writer.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Uri implements Xml\Element
|
||||
{
|
||||
/**
|
||||
* Uri element value.
|
||||
*/
|
||||
protected string $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
$writer->text(
|
||||
resolve(
|
||||
$writer->contextUri ?? '',
|
||||
$this->value
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* Important note 2: You are responsible for advancing the reader to the
|
||||
* next element. Not doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseSubTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*/
|
||||
public static function xmlDeserialize(Xml\Reader $reader)
|
||||
{
|
||||
return new self(
|
||||
resolve(
|
||||
(string) $reader->contextUri,
|
||||
$reader->readText()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
144
vendor/sabre/xml/lib/Element/XmlFragment.php
vendored
Normal file
144
vendor/sabre/xml/lib/Element/XmlFragment.php
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Element;
|
||||
|
||||
use Sabre\Xml\Element;
|
||||
use Sabre\Xml\Reader;
|
||||
use Sabre\Xml\Writer;
|
||||
|
||||
/**
|
||||
* The XmlFragment element allows you to extract a portion of your xml tree,
|
||||
* and get a well-formed xml string.
|
||||
*
|
||||
* This goes a bit beyond `innerXml` and friends, as we'll also match all the
|
||||
* correct namespaces.
|
||||
*
|
||||
* Please note that the XML fragment:
|
||||
*
|
||||
* 1. Will not have an <?xml declaration.
|
||||
* 2. Or a DTD
|
||||
* 3. It will have all the relevant xmlns attributes.
|
||||
* 4. It may not have a root element.
|
||||
*/
|
||||
class XmlFragment implements Element
|
||||
{
|
||||
/**
|
||||
* The inner XML value.
|
||||
*/
|
||||
protected string $xml;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct(string $xml)
|
||||
{
|
||||
$this->xml = $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inner XML document.
|
||||
*/
|
||||
public function getXml(): string
|
||||
{
|
||||
return $this->xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Writer $writer): void
|
||||
{
|
||||
$reader = new Reader();
|
||||
|
||||
// Wrapping the xml in a container, so root-less values can still be
|
||||
// parsed.
|
||||
$xml = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<xml-fragment xmlns="http://sabre.io/ns">{$this->getXml()}</xml-fragment>
|
||||
XML;
|
||||
|
||||
$reader->xml($xml);
|
||||
|
||||
while ($reader->read()) {
|
||||
if ($reader->depth < 1) {
|
||||
// Skipping the root node.
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($reader->nodeType) {
|
||||
case Reader::ELEMENT:
|
||||
$writer->startElement(
|
||||
(string) $reader->getClark()
|
||||
);
|
||||
$empty = $reader->isEmptyElement;
|
||||
while ($reader->moveToNextAttribute()) {
|
||||
switch ($reader->namespaceURI) {
|
||||
case '':
|
||||
$writer->writeAttribute($reader->localName, $reader->value);
|
||||
break;
|
||||
case 'http://www.w3.org/2000/xmlns/':
|
||||
// Skip namespace declarations
|
||||
break;
|
||||
default:
|
||||
$writer->writeAttribute((string) $reader->getClark(), $reader->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($empty) {
|
||||
$writer->endElement();
|
||||
}
|
||||
break;
|
||||
case Reader::CDATA:
|
||||
case Reader::TEXT:
|
||||
$writer->text(
|
||||
$reader->value
|
||||
);
|
||||
break;
|
||||
case Reader::END_ELEMENT:
|
||||
$writer->endElement();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* You are responsible for advancing the reader to the next element. Not
|
||||
* doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*/
|
||||
public static function xmlDeserialize(Reader $reader)
|
||||
{
|
||||
$result = new self($reader->readInnerXml());
|
||||
$reader->next();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
49
vendor/sabre/xml/lib/LibXMLException.php
vendored
Normal file
49
vendor/sabre/xml/lib/LibXMLException.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
use LibXMLError;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the Reader runs into a parsing error.
|
||||
*
|
||||
* This exception effectively wraps 1 or more LibXMLError objects.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class LibXMLException extends ParseException
|
||||
{
|
||||
/**
|
||||
* The error list.
|
||||
*
|
||||
* @var \LibXMLError[]
|
||||
*/
|
||||
protected array $errors;
|
||||
|
||||
/**
|
||||
* Creates the exception.
|
||||
*
|
||||
* You should pass a list of LibXMLError objects in its constructor.
|
||||
*
|
||||
* @param \LibXMLError[] $errors
|
||||
*/
|
||||
public function __construct(array $errors, int $code = 0, ?\Throwable $previousException = null)
|
||||
{
|
||||
$this->errors = $errors;
|
||||
parent::__construct($errors[0]->message.' on line '.$errors[0]->line.', column '.$errors[0]->column, $code, $previousException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LibXML errors.
|
||||
*
|
||||
* @return \LibXMLError[]
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
||||
16
vendor/sabre/xml/lib/ParseException.php
vendored
Normal file
16
vendor/sabre/xml/lib/ParseException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* This is a base exception for any exception related to parsing xml files.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class ParseException extends \Exception
|
||||
{
|
||||
}
|
||||
317
vendor/sabre/xml/lib/Reader.php
vendored
Normal file
317
vendor/sabre/xml/lib/Reader.php
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
use XMLReader;
|
||||
|
||||
/**
|
||||
* The Reader class expands upon PHP's built-in XMLReader.
|
||||
*
|
||||
* The intended usage, is to assign certain XML elements to PHP classes. These
|
||||
* need to be registered using the $elementMap public property.
|
||||
*
|
||||
* After this is done, a single call to parse() will parse the entire document,
|
||||
* and delegate sub-sections of the document to element classes.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Reader extends \XMLReader
|
||||
{
|
||||
use ContextStackTrait;
|
||||
|
||||
/**
|
||||
* Returns the current nodename in clark-notation.
|
||||
*
|
||||
* For example: "{http://www.w3.org/2005/Atom}feed".
|
||||
* Or if no namespace is defined: "{}feed".
|
||||
*
|
||||
* This method returns null if we're not currently on an element.
|
||||
*/
|
||||
public function getClark(): ?string
|
||||
{
|
||||
if (!$this->localName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return '{'.$this->namespaceURI.'}'.$this->localName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire document.
|
||||
*
|
||||
* This function returns an array with the following three elements:
|
||||
* * name - The root element name.
|
||||
* * value - The value for the root element.
|
||||
* * attributes - An array of attributes.
|
||||
*
|
||||
* This function will also disable the standard libxml error handler (which
|
||||
* usually just results in PHP errors), and throw exceptions instead.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function parse(): array
|
||||
{
|
||||
$previousEntityState = null;
|
||||
$shouldCallLibxmlDisableEntityLoader = (\LIBXML_VERSION < 20900);
|
||||
if ($shouldCallLibxmlDisableEntityLoader) {
|
||||
$previousEntityState = libxml_disable_entity_loader(true);
|
||||
}
|
||||
$previousSetting = libxml_use_internal_errors(true);
|
||||
|
||||
try {
|
||||
while (self::ELEMENT !== $this->nodeType) {
|
||||
if (!$this->read()) {
|
||||
$errors = libxml_get_errors();
|
||||
libxml_clear_errors();
|
||||
if ($errors) {
|
||||
throw new LibXMLException($errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
$result = $this->parseCurrentElement();
|
||||
|
||||
// last line of defense in case errors did occur above
|
||||
$errors = libxml_get_errors();
|
||||
libxml_clear_errors();
|
||||
if ($errors) {
|
||||
throw new LibXMLException($errors);
|
||||
}
|
||||
} finally {
|
||||
libxml_use_internal_errors($previousSetting);
|
||||
if ($shouldCallLibxmlDisableEntityLoader) {
|
||||
libxml_disable_entity_loader($previousEntityState);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseGetElements parses everything in the current sub-tree,
|
||||
* and returns an array of elements.
|
||||
*
|
||||
* Each element has a 'name', 'value' and 'attributes' key.
|
||||
*
|
||||
* If the element didn't contain sub-elements, an empty array is always
|
||||
* returned. If there was any text inside the element, it will be
|
||||
* discarded.
|
||||
*
|
||||
* If the $elementMap argument is specified, the existing elementMap will
|
||||
* be overridden while parsing the tree, and restored after this process.
|
||||
*
|
||||
* @param array<string, mixed>|null $elementMap
|
||||
*
|
||||
* @return array<int,array<string, mixed>>
|
||||
*/
|
||||
public function parseGetElements(?array $elementMap = null): array
|
||||
{
|
||||
$result = $this->parseInnerTree($elementMap);
|
||||
if (!is_array($result)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses all elements below the current element.
|
||||
*
|
||||
* This method will return a string if this was a text-node, or an array if
|
||||
* there were sub-elements.
|
||||
*
|
||||
* If there's both text and sub-elements, the text will be discarded.
|
||||
*
|
||||
* If the $elementMap argument is specified, the existing elementMap will
|
||||
* be overridden while parsing the tree, and restored after this process.
|
||||
*
|
||||
* @param array<string, mixed>|null $elementMap
|
||||
*
|
||||
* @return array<int,array<string, mixed>>|string|null
|
||||
*/
|
||||
public function parseInnerTree(?array $elementMap = null)
|
||||
{
|
||||
$text = null;
|
||||
$elements = [];
|
||||
|
||||
if (self::ELEMENT === $this->nodeType && $this->isEmptyElement) {
|
||||
// Easy!
|
||||
$this->next();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_null($elementMap)) {
|
||||
$this->pushContext();
|
||||
$this->elementMap = $elementMap;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$this->read()) {
|
||||
$errors = libxml_get_errors();
|
||||
libxml_clear_errors();
|
||||
if ($errors) {
|
||||
throw new LibXMLException($errors);
|
||||
}
|
||||
throw new ParseException('This should never happen (famous last words)');
|
||||
}
|
||||
|
||||
$keepOnParsing = true;
|
||||
|
||||
while ($keepOnParsing) {
|
||||
if (!$this->isValid()) {
|
||||
$errors = libxml_get_errors();
|
||||
|
||||
if ($errors) {
|
||||
libxml_clear_errors();
|
||||
throw new LibXMLException($errors);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->nodeType) {
|
||||
case self::ELEMENT:
|
||||
$elements[] = $this->parseCurrentElement();
|
||||
break;
|
||||
case self::TEXT:
|
||||
case self::CDATA:
|
||||
$text .= $this->value;
|
||||
$this->read();
|
||||
break;
|
||||
case self::END_ELEMENT:
|
||||
// Ensuring we are moving the cursor after the end element.
|
||||
$this->read();
|
||||
$keepOnParsing = false;
|
||||
break;
|
||||
case self::NONE:
|
||||
throw new ParseException('We hit the end of the document prematurely. This likely means that some parser "eats" too many elements. Do not attempt to continue parsing.');
|
||||
default:
|
||||
// Advance to the next element
|
||||
$this->read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (!is_null($elementMap)) {
|
||||
$this->popContext();
|
||||
}
|
||||
}
|
||||
|
||||
return $elements ?: $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all text below the current element, and returns this as a string.
|
||||
*/
|
||||
public function readText(): string
|
||||
{
|
||||
$result = '';
|
||||
$previousDepth = $this->depth;
|
||||
|
||||
while ($this->read() && $this->depth != $previousDepth) {
|
||||
if (in_array($this->nodeType, [\XMLReader::TEXT, \XMLReader::CDATA, \XMLReader::WHITESPACE])) {
|
||||
$result .= $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the current XML element.
|
||||
*
|
||||
* This method returns arn array with 3 properties:
|
||||
* * name - A clark-notation XML element name.
|
||||
* * value - The parsed value.
|
||||
* * attributes - A key-value list of attributes.
|
||||
*
|
||||
* @return array <string, mixed>
|
||||
*/
|
||||
public function parseCurrentElement(): array
|
||||
{
|
||||
$name = $this->getClark();
|
||||
|
||||
$attributes = [];
|
||||
|
||||
if ($this->hasAttributes) {
|
||||
$attributes = $this->parseAttributes();
|
||||
}
|
||||
|
||||
$value = call_user_func(
|
||||
$this->getDeserializerForElementName((string) $name),
|
||||
$this
|
||||
);
|
||||
|
||||
return [
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
'attributes' => $attributes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs all the attributes from the current element, and returns them as a
|
||||
* key-value array.
|
||||
*
|
||||
* If the attributes are part of the same namespace, they will simply be
|
||||
* short keys. If they are defined on a different namespace, the attribute
|
||||
* name will be returned in clark-notation.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function parseAttributes(): array
|
||||
{
|
||||
$attributes = [];
|
||||
|
||||
while ($this->moveToNextAttribute()) {
|
||||
if ($this->namespaceURI) {
|
||||
// Ignoring 'xmlns', it doesn't make any sense.
|
||||
if ('http://www.w3.org/2000/xmlns/' === $this->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $this->getClark();
|
||||
$attributes[$name] = $this->value;
|
||||
} else {
|
||||
$attributes[$this->localName] = $this->value;
|
||||
}
|
||||
}
|
||||
$this->moveToElement();
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function that should be used to parse the element identified
|
||||
* by its clark-notation name.
|
||||
*/
|
||||
public function getDeserializerForElementName(string $name): callable
|
||||
{
|
||||
if (!array_key_exists($name, $this->elementMap)) {
|
||||
if ('{}' == substr($name, 0, 2) && array_key_exists(substr($name, 2), $this->elementMap)) {
|
||||
$name = substr($name, 2);
|
||||
} else {
|
||||
return ['Sabre\\Xml\\Element\\Base', 'xmlDeserialize'];
|
||||
}
|
||||
}
|
||||
|
||||
$deserializer = $this->elementMap[$name];
|
||||
if (is_callable($deserializer)) {
|
||||
return $deserializer;
|
||||
}
|
||||
|
||||
if (is_subclass_of($deserializer, 'Sabre\\Xml\\XmlDeserializable')) {
|
||||
return [$deserializer, 'xmlDeserialize'];
|
||||
}
|
||||
|
||||
$type = gettype($deserializer);
|
||||
if (is_string($deserializer)) {
|
||||
$type .= ' ('.$deserializer.')';
|
||||
} elseif (is_object($deserializer)) {
|
||||
$type .= ' ('.get_class($deserializer).')';
|
||||
}
|
||||
throw new \LogicException('Could not use this type as a deserializer: '.$type.' for element: '.$name);
|
||||
}
|
||||
}
|
||||
207
vendor/sabre/xml/lib/Serializer/functions.php
vendored
Normal file
207
vendor/sabre/xml/lib/Serializer/functions.php
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml\Serializer;
|
||||
|
||||
use Sabre\Xml\Writer;
|
||||
use Sabre\Xml\XmlSerializable;
|
||||
|
||||
/**
|
||||
* This file provides a number of 'serializer' helper functions.
|
||||
*
|
||||
* These helper functions can be used to easily xml-encode common PHP
|
||||
* data structures, or can be placed in the $classMap.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The 'enum' serializer writes simple list of elements.
|
||||
*
|
||||
* For example, calling:
|
||||
*
|
||||
* enum($writer, [
|
||||
* "{http://sabredav.org/ns}elem1",
|
||||
* "{http://sabredav.org/ns}elem2",
|
||||
* "{http://sabredav.org/ns}elem3",
|
||||
* "{http://sabredav.org/ns}elem4",
|
||||
* "{http://sabredav.org/ns}elem5",
|
||||
* ]);
|
||||
*
|
||||
* Will generate something like this (if the correct namespace is declared):
|
||||
*
|
||||
* <s:elem1 />
|
||||
* <s:elem2 />
|
||||
* <s:elem3 />
|
||||
* <s:elem4>content</s:elem4>
|
||||
* <s:elem5 attr="val" />
|
||||
*
|
||||
* @param string[] $values
|
||||
*/
|
||||
function enum(Writer $writer, array $values): void
|
||||
{
|
||||
foreach ($values as $value) {
|
||||
$writer->writeElement($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The valueObject serializer turns a simple PHP object into a classname.
|
||||
*
|
||||
* Every public property will be encoded as an XML element with the same
|
||||
* name, in the XML namespace as specified.
|
||||
*
|
||||
* Values that are set to null or an empty array are not serialized. To
|
||||
* serialize empty properties, you must specify them as an empty string.
|
||||
*/
|
||||
function valueObject(Writer $writer, object $valueObject, string $namespace): void
|
||||
{
|
||||
foreach (get_object_vars($valueObject) as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
// If $val is an array, it has a special meaning. We need to
|
||||
// generate one child element for each item in $val
|
||||
foreach ($val as $child) {
|
||||
$writer->writeElement('{'.$namespace.'}'.$key, $child);
|
||||
}
|
||||
} elseif (null !== $val) {
|
||||
$writer->writeElement('{'.$namespace.'}'.$key, $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This serializer helps you serialize xml structures that look like
|
||||
* this:.
|
||||
*
|
||||
* <collection>
|
||||
* <item>...</item>
|
||||
* <item>...</item>
|
||||
* <item>...</item>
|
||||
* </collection>
|
||||
*
|
||||
* In that previous example, this serializer just serializes the item element,
|
||||
* and this could be called like this:
|
||||
*
|
||||
* repeatingElements($writer, $items, '{}item');
|
||||
*
|
||||
* @param array<int,mixed> $items
|
||||
*/
|
||||
function repeatingElements(Writer $writer, array $items, string $childElementName): void
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
$writer->writeElement($childElementName, $item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is the 'default' serializer that is able to serialize most
|
||||
* things, and delegates to other serializers if needed.
|
||||
*
|
||||
* The standardSerializer supports a wide-array of values.
|
||||
*
|
||||
* $value may be a string or integer, it will just write out the string as text.
|
||||
* $value may be an instance of XmlSerializable or Element, in which case it
|
||||
* calls it's xmlSerialize() method.
|
||||
* $value may be a PHP callback/function/closure, in case we call the callback
|
||||
* and give it the Writer as an argument.
|
||||
* $value may be an object, and if it's in the classMap we automatically call
|
||||
* the correct serializer for it.
|
||||
* $value may be null, in which case we do nothing.
|
||||
*
|
||||
* If $value is an array, the array must look like this:
|
||||
*
|
||||
* [
|
||||
* [
|
||||
* 'name' => '{namespaceUri}element-name',
|
||||
* 'value' => '...',
|
||||
* 'attributes' => [ 'attName' => 'attValue' ]
|
||||
* ]
|
||||
* [,
|
||||
* 'name' => '{namespaceUri}element-name2',
|
||||
* 'value' => '...',
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* This would result in xml like:
|
||||
*
|
||||
* <element-name xmlns="namespaceUri" attName="attValue">
|
||||
* ...
|
||||
* </element-name>
|
||||
* <element-name2>
|
||||
* ...
|
||||
* </element-name2>
|
||||
*
|
||||
* The value property may be any value standardSerializer supports, so you can
|
||||
* nest data-structures this way. Both value and attributes are optional.
|
||||
*
|
||||
* Alternatively, you can also specify the array using this syntax:
|
||||
*
|
||||
* [
|
||||
* [
|
||||
* '{namespaceUri}element-name' => '...',
|
||||
* '{namespaceUri}element-name2' => '...',
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* This is excellent for simple key->value structures, and here you can also
|
||||
* specify anything for the value.
|
||||
*
|
||||
* You can even mix the two array syntaxes.
|
||||
*
|
||||
* @param string|int|float|bool|array<int|string, mixed>|object $value
|
||||
*/
|
||||
function standardSerializer(Writer $writer, $value): void
|
||||
{
|
||||
if (is_scalar($value)) {
|
||||
// String, integer, float, boolean
|
||||
$writer->text((string) $value);
|
||||
} elseif ($value instanceof XmlSerializable) {
|
||||
// XmlSerializable classes or Element classes.
|
||||
$value->xmlSerialize($writer);
|
||||
} elseif (is_object($value) && isset($writer->classMap[get_class($value)])) {
|
||||
// It's an object which class appears in the classmap.
|
||||
$writer->classMap[get_class($value)]($writer, $value);
|
||||
} elseif (is_callable($value)) {
|
||||
// A callback
|
||||
$value($writer);
|
||||
} elseif (is_array($value) && array_key_exists('name', $value)) {
|
||||
// if the array had a 'name' element, we assume that this array
|
||||
// describes a 'name' and optionally 'attributes' and 'value'.
|
||||
|
||||
$name = $value['name'];
|
||||
$attributes = isset($value['attributes']) ? $value['attributes'] : [];
|
||||
$value = isset($value['value']) ? $value['value'] : null;
|
||||
|
||||
$writer->startElement($name);
|
||||
$writer->writeAttributes($attributes);
|
||||
$writer->write($value);
|
||||
$writer->endElement();
|
||||
} elseif (is_array($value)) {
|
||||
foreach ($value as $name => $item) {
|
||||
if (is_int($name)) {
|
||||
// This item has a numeric index. We just loop through the
|
||||
// array and throw it back in the writer.
|
||||
standardSerializer($writer, $item);
|
||||
} elseif (is_string($name) && is_array($item) && isset($item['attributes'])) {
|
||||
// The key is used for a name, but $item has 'attributes' and
|
||||
// possibly 'value'
|
||||
$writer->startElement($name);
|
||||
$writer->writeAttributes($item['attributes']);
|
||||
if (isset($item['value'])) {
|
||||
$writer->write($item['value']);
|
||||
}
|
||||
$writer->endElement();
|
||||
} elseif (is_string($name)) {
|
||||
// This was a plain key-value array.
|
||||
$writer->startElement($name);
|
||||
$writer->write($item);
|
||||
$writer->endElement();
|
||||
} else {
|
||||
throw new \InvalidArgumentException('The writer does not know how to serialize arrays with keys of type: '.gettype($name));
|
||||
}
|
||||
}
|
||||
} elseif (is_object($value)) {
|
||||
throw new \InvalidArgumentException('The writer cannot serialize objects of class: '.get_class($value));
|
||||
} elseif (!is_null($value)) {
|
||||
throw new \InvalidArgumentException('The writer cannot serialize values of type: '.gettype($value));
|
||||
}
|
||||
}
|
||||
326
vendor/sabre/xml/lib/Service.php
vendored
Normal file
326
vendor/sabre/xml/lib/Service.php
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* XML parsing and writing service.
|
||||
*
|
||||
* You are encouraged to make an instance of this for your application and
|
||||
* potentially extend it, as a central API point for dealing with xml and
|
||||
* configuring the reader and writer.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Service
|
||||
{
|
||||
/**
|
||||
* This is the element map. It contains a list of XML elements (in clark
|
||||
* notation) as keys and PHP class names as values.
|
||||
*
|
||||
* The PHP class names must implement Sabre\Xml\Element.
|
||||
*
|
||||
* Values may also be a callable. In that case the function will be called
|
||||
* directly.
|
||||
*
|
||||
* @phpstan-var array<string, class-string|callable|object>
|
||||
*/
|
||||
public array $elementMap = [];
|
||||
|
||||
/**
|
||||
* This is a list of namespaces that you want to give default prefixes.
|
||||
*
|
||||
* You must make sure you create this entire list before starting to write.
|
||||
* They should be registered on the root element.
|
||||
*
|
||||
* @phpstan-var array<string, class-string|string|null>
|
||||
*/
|
||||
public array $namespaceMap = [];
|
||||
|
||||
/**
|
||||
* This is a list of custom serializers for specific classes.
|
||||
*
|
||||
* The writer may use this if you attempt to serialize an object with a
|
||||
* class that does not implement XmlSerializable.
|
||||
*
|
||||
* Instead, it will look at this classmap to see if there is a custom
|
||||
* serializer here. This is useful if you don't want your value objects
|
||||
* to be responsible for serializing themselves.
|
||||
*
|
||||
* The keys in this classmap need to be fully qualified PHP class names,
|
||||
* the values must be callbacks. The callbacks take two arguments. The
|
||||
* writer class, and the value that must be written.
|
||||
*
|
||||
* function (Writer $writer, object $value)
|
||||
*
|
||||
* @phpstan-var array<class-string, callable(Writer, object):mixed>
|
||||
*/
|
||||
public array $classMap = [];
|
||||
|
||||
/**
|
||||
* A bitmask of the LIBXML_* constants.
|
||||
*/
|
||||
public int $options = 0;
|
||||
|
||||
/**
|
||||
* Returns a fresh XML Reader.
|
||||
*/
|
||||
public function getReader(): Reader
|
||||
{
|
||||
$r = new Reader();
|
||||
$r->elementMap = $this->elementMap;
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fresh xml writer.
|
||||
*/
|
||||
public function getWriter(): Writer
|
||||
{
|
||||
$w = new Writer();
|
||||
$w->namespaceMap = $this->namespaceMap;
|
||||
$w->classMap = $this->classMap;
|
||||
|
||||
return $w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a document in full.
|
||||
*
|
||||
* Input may be specified as a string or readable stream resource.
|
||||
* The returned value is the value of the root document.
|
||||
*
|
||||
* Specifying the $contextUri allows the parser to figure out what the URI
|
||||
* of the document was. This allows relative URIs within the document to be
|
||||
* expanded easily.
|
||||
*
|
||||
* The $rootElementName is specified by reference and will be populated
|
||||
* with the root element name of the document.
|
||||
*
|
||||
* @param string|resource $input
|
||||
*
|
||||
* @return array<string, mixed>|object|string
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public function parse($input, ?string $contextUri = null, ?string &$rootElementName = null)
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
// Unfortunately the XMLReader doesn't support streams. When it
|
||||
// does, we can optimize this.
|
||||
if (is_resource($input)) {
|
||||
$input = (string) stream_get_contents($input);
|
||||
} else {
|
||||
// Input is not a string and not a resource.
|
||||
// Therefore, it has to be a closed resource.
|
||||
// Effectively empty input has been passed in.
|
||||
$input = '';
|
||||
}
|
||||
}
|
||||
|
||||
// If input is empty, then it's safe to throw an exception
|
||||
if (empty($input)) {
|
||||
throw new ParseException('The input element to parse is empty. Do not attempt to parse');
|
||||
}
|
||||
|
||||
$r = $this->getReader();
|
||||
$r->contextUri = $contextUri;
|
||||
$r->XML($input, null, $this->options);
|
||||
|
||||
$result = $r->parse();
|
||||
$rootElementName = $result['name'];
|
||||
|
||||
return $result['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a document in full, and specify what the expected root element
|
||||
* name is.
|
||||
*
|
||||
* This function works similar to parse, but the difference is that the
|
||||
* user can specify what the expected name of the root element should be,
|
||||
* in clark notation.
|
||||
*
|
||||
* This is useful in cases where you expected a specific document to be
|
||||
* passed, and reduces the amount of if statements.
|
||||
*
|
||||
* It's also possible to pass an array of expected rootElements if your
|
||||
* code may expect more than one document type.
|
||||
*
|
||||
* @param string|string[] $rootElementName
|
||||
* @param string|resource $input
|
||||
*
|
||||
* @return array<string, mixed>|object|string
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public function expect($rootElementName, $input, ?string $contextUri = null)
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
// Unfortunately the XMLReader doesn't support streams. When it
|
||||
// does, we can optimize this.
|
||||
if (is_resource($input)) {
|
||||
$input = (string) stream_get_contents($input);
|
||||
} else {
|
||||
// Input is not a string and not a resource.
|
||||
// Therefore, it has to be a closed resource.
|
||||
// Effectively empty input has been passed in.
|
||||
$input = '';
|
||||
}
|
||||
}
|
||||
|
||||
// If input is empty, then it's safe to throw an exception
|
||||
if (empty($input)) {
|
||||
throw new ParseException('The input element to parse is empty. Do not attempt to parse');
|
||||
}
|
||||
|
||||
$r = $this->getReader();
|
||||
$r->contextUri = $contextUri;
|
||||
$r->XML($input, null, $this->options);
|
||||
|
||||
$rootElementName = (array) $rootElementName;
|
||||
|
||||
foreach ($rootElementName as &$rEl) {
|
||||
if ('{' !== $rEl[0]) {
|
||||
$rEl = '{}'.$rEl;
|
||||
}
|
||||
}
|
||||
|
||||
$result = $r->parse();
|
||||
if (!in_array($result['name'], $rootElementName, true)) {
|
||||
throw new ParseException('Expected '.implode(' or ', $rootElementName).' but received '.$result['name'].' as the root element');
|
||||
}
|
||||
|
||||
return $result['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an XML document in one go.
|
||||
*
|
||||
* The $rootElement must be specified in clark notation.
|
||||
* The value must be a string, an array or an object implementing
|
||||
* XmlSerializable. Basically, anything that's supported by the Writer
|
||||
* object.
|
||||
*
|
||||
* $contextUri can be used to specify a sort of 'root' of the PHP application,
|
||||
* in case the xml document is used as a http response.
|
||||
*
|
||||
* This allows an implementor to easily create URI's relative to the root
|
||||
* of the domain.
|
||||
*
|
||||
* @param string|array<int|string, mixed>|object|XmlSerializable $value
|
||||
*/
|
||||
public function write(string $rootElementName, $value, ?string $contextUri = null): string
|
||||
{
|
||||
$w = $this->getWriter();
|
||||
$w->openMemory();
|
||||
$w->contextUri = $contextUri;
|
||||
$w->setIndent(true);
|
||||
$w->startDocument();
|
||||
$w->writeElement($rootElementName, $value);
|
||||
|
||||
return $w->outputMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Map an XML element to a PHP class.
|
||||
*
|
||||
* Calling this function will automatically set up the Reader and Writer
|
||||
* classes to turn a specific XML element to a PHP class.
|
||||
*
|
||||
* For example, given a class such as :
|
||||
*
|
||||
* class Author {
|
||||
* public $firstName;
|
||||
* public $lastName;
|
||||
* }
|
||||
*
|
||||
* and an XML element such as:
|
||||
*
|
||||
* <author xmlns="http://example.org/ns">
|
||||
* <firstName>...</firstName>
|
||||
* <lastName>...</lastName>
|
||||
* </author>
|
||||
*
|
||||
* These can easily be mapped by calling:
|
||||
*
|
||||
* $service->mapValueObject('{http://example.org}author', 'Author');
|
||||
*
|
||||
* @param class-string $className
|
||||
*/
|
||||
public function mapValueObject(string $elementName, string $className): void
|
||||
{
|
||||
list($namespace) = self::parseClarkNotation($elementName);
|
||||
|
||||
$this->elementMap[$elementName] = function (Reader $reader) use ($className, $namespace) {
|
||||
return \Sabre\Xml\Deserializer\valueObject($reader, $className, $namespace);
|
||||
};
|
||||
$this->classMap[$className] = function (Writer $writer, $valueObject) use ($namespace) {
|
||||
\Sabre\Xml\Serializer\valueObject($writer, $valueObject, $namespace);
|
||||
};
|
||||
$this->valueObjectMap[$className] = $elementName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value object.
|
||||
*
|
||||
* This function largely behaves similar to write(), except that it's
|
||||
* intended specifically to serialize a Value Object into an XML document.
|
||||
*
|
||||
* The ValueObject must have been previously registered using
|
||||
* mapValueObject().
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function writeValueObject(object $object, ?string $contextUri = null): string
|
||||
{
|
||||
if (!isset($this->valueObjectMap[get_class($object)])) {
|
||||
throw new \InvalidArgumentException('"'.get_class($object).'" is not a registered value object class. Register your class with mapValueObject.');
|
||||
}
|
||||
|
||||
return $this->write(
|
||||
$this->valueObjectMap[get_class($object)],
|
||||
$object,
|
||||
$contextUri
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a clark-notation string, and returns the namespace and element
|
||||
* name components.
|
||||
*
|
||||
* If the string was invalid, it will throw an InvalidArgumentException.
|
||||
*
|
||||
* @return array{string, string}
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function parseClarkNotation(string $str): array
|
||||
{
|
||||
static $cache = [];
|
||||
|
||||
if (!isset($cache[$str])) {
|
||||
if (!preg_match('/^{([^}]*)}(.*)$/', $str, $matches)) {
|
||||
throw new \InvalidArgumentException('\''.$str.'\' is not a valid clark-notation formatted string');
|
||||
}
|
||||
|
||||
$cache[$str] = [
|
||||
$matches[1],
|
||||
$matches[2],
|
||||
];
|
||||
}
|
||||
|
||||
return $cache[$str];
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of classes and which XML elements they map to.
|
||||
*
|
||||
* @var array<class-string, string>
|
||||
*/
|
||||
protected array $valueObjectMap = [];
|
||||
}
|
||||
20
vendor/sabre/xml/lib/Version.php
vendored
Normal file
20
vendor/sabre/xml/lib/Version.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* This class contains the version number for this package.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* Full version number.
|
||||
*/
|
||||
public const VERSION = '4.0.6';
|
||||
}
|
||||
261
vendor/sabre/xml/lib/Writer.php
vendored
Normal file
261
vendor/sabre/xml/lib/Writer.php
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
use XMLWriter;
|
||||
|
||||
/**
|
||||
* The XML Writer class.
|
||||
*
|
||||
* This class works exactly as PHP's built-in XMLWriter, with a few additions.
|
||||
*
|
||||
* Namespaces can be registered beforehand, globally. When the first element is
|
||||
* written, namespaces will automatically be declared.
|
||||
*
|
||||
* The writeAttribute, startElement and writeElement can now take a
|
||||
* clark-notation element name (example: {http://www.w3.org/2005/Atom}link).
|
||||
*
|
||||
* If, when writing the namespace is a known one a prefix will automatically be
|
||||
* selected, otherwise a random prefix will be generated.
|
||||
*
|
||||
* Instead of standard string values, the writer can take Element classes (as
|
||||
* defined by this library) to delegate the serialization.
|
||||
*
|
||||
* The write() method can take array structures to quickly write out simple xml
|
||||
* trees.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Writer extends \XMLWriter
|
||||
{
|
||||
use ContextStackTrait;
|
||||
|
||||
/**
|
||||
* Any namespace that the writer is asked to write, will be added here.
|
||||
*
|
||||
* Any of these elements will get a new namespace definition *every single
|
||||
* time* they are used, but this array allows the writer to make sure that
|
||||
* the prefixes are consistent anyway.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $adhocNamespaces = [];
|
||||
|
||||
/**
|
||||
* When the first element is written, this flag is set to true.
|
||||
*
|
||||
* This ensures that the namespaces in the namespaces map are only written
|
||||
* once.
|
||||
*/
|
||||
protected bool $namespacesWritten = false;
|
||||
|
||||
/**
|
||||
* Writes a value to the output stream.
|
||||
*
|
||||
* The following values are supported:
|
||||
* 1. Scalar values will be written as-is, as text.
|
||||
* 2. Null values will be skipped (resulting in a short xml tag).
|
||||
* 3. If a value is an instance of an Element class, writing will be
|
||||
* delegated to the object.
|
||||
* 4. If a value is an array, two formats are supported.
|
||||
*
|
||||
* Array format 1:
|
||||
* [
|
||||
* "{namespace}name1" => "..",
|
||||
* "{namespace}name2" => "..",
|
||||
* ]
|
||||
*
|
||||
* One element will be created for each key in this array. The values of
|
||||
* this array support any format this method supports (this method is
|
||||
* called recursively).
|
||||
*
|
||||
* Array format 2:
|
||||
*
|
||||
* [
|
||||
* [
|
||||
* "name" => "{namespace}name1"
|
||||
* "value" => "..",
|
||||
* "attributes" => [
|
||||
* "attr" => "attribute value",
|
||||
* ]
|
||||
* ],
|
||||
* [
|
||||
* "name" => "{namespace}name1"
|
||||
* "value" => "..",
|
||||
* "attributes" => [
|
||||
* "attr" => "attribute value",
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @param mixed $value PHP value to be written
|
||||
*/
|
||||
public function write($value): void
|
||||
{
|
||||
Serializer\standardSerializer($this, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new element.
|
||||
*
|
||||
* You can either just use a local element name, or you can use clark-
|
||||
* notation to start a new element.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $writer->startElement('{http://www.w3.org/2005/Atom}entry');
|
||||
*
|
||||
* Would result in something like:
|
||||
*
|
||||
* <entry xmlns="http://w3.org/2005/Atom">
|
||||
*
|
||||
* Note: this function doesn't have the string typehint, because PHP's
|
||||
* XMLWriter::startElement doesn't either.
|
||||
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function startElement($name): bool
|
||||
{
|
||||
if ('{' === $name[0]) {
|
||||
list($namespace, $localName) =
|
||||
Service::parseClarkNotation($name);
|
||||
|
||||
if (array_key_exists($namespace, $this->namespaceMap)) {
|
||||
$result = $this->startElementNS(
|
||||
'' === $this->namespaceMap[$namespace] ? null : $this->namespaceMap[$namespace],
|
||||
$localName,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
// An empty namespace means it's the global namespace. This is
|
||||
// allowed, but it mustn't get a prefix.
|
||||
if ('' === $namespace) {
|
||||
$result = $this->startElement($localName);
|
||||
$this->writeAttribute('xmlns', '');
|
||||
} else {
|
||||
if (!isset($this->adhocNamespaces[$namespace])) {
|
||||
$this->adhocNamespaces[$namespace] = 'x'.(count($this->adhocNamespaces) + 1);
|
||||
}
|
||||
$result = $this->startElementNS($this->adhocNamespaces[$namespace], $localName, $namespace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$result = parent::startElement($name);
|
||||
}
|
||||
|
||||
if (!$this->namespacesWritten) {
|
||||
foreach ($this->namespaceMap as $namespace => $prefix) {
|
||||
$this->writeAttribute($prefix ? 'xmlns:'.$prefix : 'xmlns', $namespace);
|
||||
}
|
||||
$this->namespacesWritten = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a full element tag and it's contents.
|
||||
*
|
||||
* This method automatically closes the element as well.
|
||||
*
|
||||
* The element name may be specified in clark-notation.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* $writer->writeElement('{http://www.w3.org/2005/Atom}author',null);
|
||||
* becomes:
|
||||
* <author xmlns="http://www.w3.org/2005" />
|
||||
*
|
||||
* $writer->writeElement('{http://www.w3.org/2005/Atom}author', [
|
||||
* '{http://www.w3.org/2005/Atom}name' => 'Evert Pot',
|
||||
* ]);
|
||||
* becomes:
|
||||
* <author xmlns="http://www.w3.org/2005" /><name>Evert Pot</name></author>
|
||||
*
|
||||
* Note: this function doesn't have the string typehint, because PHP's
|
||||
* XMLWriter::startElement doesn't either.
|
||||
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array<int|string, mixed>|string|object|null $content
|
||||
*/
|
||||
public function writeElement($name, $content = null): bool
|
||||
{
|
||||
$this->startElement($name);
|
||||
if (!is_null($content)) {
|
||||
$this->write($content);
|
||||
}
|
||||
$this->endElement();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a list of attributes.
|
||||
*
|
||||
* Attributes are specified as a key->value array.
|
||||
*
|
||||
* The key is an attribute name. If the key is a 'localName', the current
|
||||
* xml namespace is assumed. If it's a 'clark notation key', this namespace
|
||||
* will be used instead.
|
||||
*
|
||||
* @param array<string, string> $attributes
|
||||
*/
|
||||
public function writeAttributes(array $attributes): void
|
||||
{
|
||||
foreach ($attributes as $name => $value) {
|
||||
$this->writeAttribute($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a new attribute.
|
||||
*
|
||||
* The name may be specified in clark-notation.
|
||||
*
|
||||
* Returns true when successful.
|
||||
*
|
||||
* Note: this function doesn't have typehints, because for some reason
|
||||
* PHP's XMLWriter::writeAttribute doesn't either.
|
||||
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function writeAttribute($name, $value): bool
|
||||
{
|
||||
if ('{' !== $name[0]) {
|
||||
return parent::writeAttribute($name, $value);
|
||||
}
|
||||
|
||||
list(
|
||||
$namespace,
|
||||
$localName,
|
||||
) = Service::parseClarkNotation($name);
|
||||
|
||||
if (array_key_exists($namespace, $this->namespaceMap)) {
|
||||
// It's an attribute with a namespace we know
|
||||
return $this->writeAttribute(
|
||||
$this->namespaceMap[$namespace].':'.$localName,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
// We don't know the namespace, we must add it in-line
|
||||
if (!isset($this->adhocNamespaces[$namespace])) {
|
||||
$this->adhocNamespaces[$namespace] = 'x'.(count($this->adhocNamespaces) + 1);
|
||||
}
|
||||
|
||||
return $this->writeAttributeNS(
|
||||
$this->adhocNamespaces[$namespace],
|
||||
$localName,
|
||||
$namespace,
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
38
vendor/sabre/xml/lib/XmlDeserializable.php
vendored
Normal file
38
vendor/sabre/xml/lib/XmlDeserializable.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* Implementing the XmlDeserializable interface allows you to use a class as a
|
||||
* deserializer for a specific element.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
interface XmlDeserializable
|
||||
{
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called statically, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* You are responsible for advancing the reader to the next element. Not
|
||||
* doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @return mixed see comments above
|
||||
*/
|
||||
public static function xmlDeserialize(Reader $reader);
|
||||
}
|
||||
34
vendor/sabre/xml/lib/XmlSerializable.php
vendored
Normal file
34
vendor/sabre/xml/lib/XmlSerializable.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Xml;
|
||||
|
||||
/**
|
||||
* Objects implementing XmlSerializable can control how they are represented in
|
||||
* Xml.
|
||||
*
|
||||
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
interface XmlSerializable
|
||||
{
|
||||
/**
|
||||
* The xmlSerialize method is called during xml writing.
|
||||
*
|
||||
* Use the $writer argument to write its own xml serialization.
|
||||
*
|
||||
* An important note: do _not_ create a parent element. Any element
|
||||
* implementing XmlSerializable should only ever write what's considered
|
||||
* its 'inner xml'.
|
||||
*
|
||||
* The parent of the current element is responsible for writing a
|
||||
* containing element.
|
||||
*
|
||||
* This allows serializers to be re-used for different element names.
|
||||
*
|
||||
* If you are opening new elements, you must also close them again.
|
||||
*/
|
||||
public function xmlSerialize(Writer $writer): void;
|
||||
}
|
||||
Reference in New Issue
Block a user