mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-12-30 16:40:28 +01:00
250 lines
7.0 KiB
PHP
250 lines
7.0 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Sabre\Xml\Serializer;
|
||
|
|
||
|
use InvalidArgumentException;
|
||
|
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 Writer $writer
|
||
|
* @param string[] $values
|
||
|
* @return void
|
||
|
*/
|
||
|
function enum(Writer $writer, array $values) {
|
||
|
|
||
|
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.
|
||
|
*
|
||
|
* @param Writer $writer
|
||
|
* @param object $valueObject
|
||
|
* @param string $namespace
|
||
|
*/
|
||
|
function valueObject(Writer $writer, $valueObject, $namespace) {
|
||
|
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 ($val !== null) {
|
||
|
$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 Writer $writer
|
||
|
* @param array $items A list of items sabre/xml can serialize.
|
||
|
* @param string $childElementName Element name in clark-notation
|
||
|
* @return void
|
||
|
*/
|
||
|
function repeatingElements(Writer $writer, array $items, $childElementName) {
|
||
|
|
||
|
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 a 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 Writer $writer
|
||
|
* @param string|int|float|bool|array|object
|
||
|
* @return void
|
||
|
*/
|
||
|
function standardSerializer(Writer $writer, $value) {
|
||
|
|
||
|
if (is_scalar($value)) {
|
||
|
|
||
|
// String, integer, float, boolean
|
||
|
$writer->text($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_null($value)) {
|
||
|
|
||
|
// nothing!
|
||
|
|
||
|
} 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));
|
||
|
|
||
|
} else {
|
||
|
|
||
|
throw new InvalidArgumentException('The writer cannot serialize values of type: ' . gettype($value));
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|