aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/vobject/lib/Parser/XML.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/vobject/lib/Parser/XML.php')
-rw-r--r--vendor/sabre/vobject/lib/Parser/XML.php428
1 files changed, 428 insertions, 0 deletions
diff --git a/vendor/sabre/vobject/lib/Parser/XML.php b/vendor/sabre/vobject/lib/Parser/XML.php
new file mode 100644
index 000000000..060a7fe2e
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/XML.php
@@ -0,0 +1,428 @@
+<?php
+
+namespace Sabre\VObject\Parser;
+
+use Sabre\VObject\Component;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\EofException;
+use Sabre\VObject\ParseException;
+use Sabre\Xml as SabreXml;
+
+/**
+ * XML Parser.
+ *
+ * This parser parses both the xCal and xCard formats.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class XML extends Parser {
+
+ const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
+ const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
+
+ /**
+ * The input data.
+ *
+ * @var array
+ */
+ protected $input;
+
+ /**
+ * A pointer/reference to the input.
+ *
+ * @var array
+ */
+ private $pointer;
+
+ /**
+ * Document, root component.
+ *
+ * @var Sabre\VObject\Document
+ */
+ protected $root;
+
+ /**
+ * Creates the parser.
+ *
+ * Optionally, it's possible to parse the input stream here.
+ *
+ * @param mixed $input
+ * @param int $options Any parser options (OPTION constants).
+ *
+ * @return void
+ */
+ function __construct($input = null, $options = 0) {
+
+ if (0 === $options) {
+ $options = parent::OPTION_FORGIVING;
+ }
+
+ parent::__construct($input, $options);
+
+ }
+
+ /**
+ * Parse xCal or xCard.
+ *
+ * @param resource|string $input
+ * @param int $options
+ *
+ * @throws \Exception
+ *
+ * @return Sabre\VObject\Document
+ */
+ function parse($input = null, $options = 0) {
+
+ if (!is_null($input)) {
+ $this->setInput($input);
+ }
+
+ if (0 !== $options) {
+ $this->options = $options;
+ }
+
+ if (is_null($this->input)) {
+ throw new EofException('End of input stream, or no input supplied');
+ }
+
+ switch ($this->input['name']) {
+
+ case '{' . self::XCAL_NAMESPACE . '}icalendar':
+ $this->root = new VCalendar([], false);
+ $this->pointer = &$this->input['value'][0];
+ $this->parseVCalendarComponents($this->root);
+ break;
+
+ case '{' . self::XCARD_NAMESPACE . '}vcards':
+ foreach ($this->input['value'] as &$vCard) {
+
+ $this->root = new VCard(['version' => '4.0'], false);
+ $this->pointer = &$vCard;
+ $this->parseVCardComponents($this->root);
+
+ // We just parse the first <vcard /> element.
+ break;
+
+ }
+ break;
+
+ default:
+ throw new ParseException('Unsupported XML standard');
+
+ }
+
+ return $this->root;
+ }
+
+ /**
+ * Parse a xCalendar component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseVCalendarComponents(Component $parentComponent) {
+
+ foreach ($this->pointer['value'] ?: [] as $children) {
+
+ switch (static::getTagName($children['name'])) {
+
+ case 'properties':
+ $this->pointer = &$children['value'];
+ $this->parseProperties($parentComponent);
+ break;
+
+ case 'components':
+ $this->pointer = &$children;
+ $this->parseComponent($parentComponent);
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * Parse a xCard component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseVCardComponents(Component $parentComponent) {
+
+ $this->pointer = &$this->pointer['value'];
+ $this->parseProperties($parentComponent);
+
+ }
+
+ /**
+ * Parse xCalendar and xCard properties.
+ *
+ * @param Component $parentComponent
+ * @param string $propertyNamePrefix
+ *
+ * @return void
+ */
+ protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '') {
+
+ foreach ($this->pointer ?: [] as $xmlProperty) {
+
+ list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
+
+ $propertyName = $tagName;
+ $propertyValue = [];
+ $propertyParameters = [];
+ $propertyType = 'text';
+
+ // A property which is not part of the standard.
+ if ($namespace !== self::XCAL_NAMESPACE
+ && $namespace !== self::XCARD_NAMESPACE) {
+
+ $propertyName = 'xml';
+ $value = '<' . $tagName . ' xmlns="' . $namespace . '"';
+
+ foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
+ $value .= ' ' . $attributeName . '="' . str_replace('"', '\"', $attributeValue) . '"';
+ }
+
+ $value .= '>' . $xmlProperty['value'] . '</' . $tagName . '>';
+
+ $propertyValue = [$value];
+
+ $this->createProperty(
+ $parentComponent,
+ $propertyName,
+ $propertyParameters,
+ $propertyType,
+ $propertyValue
+ );
+
+ continue;
+ }
+
+ // xCard group.
+ if ($propertyName === 'group') {
+
+ if (!isset($xmlProperty['attributes']['name'])) {
+ continue;
+ }
+
+ $this->pointer = &$xmlProperty['value'];
+ $this->parseProperties(
+ $parentComponent,
+ strtoupper($xmlProperty['attributes']['name']) . '.'
+ );
+
+ continue;
+
+ }
+
+ // Collect parameters.
+ foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
+
+ if (!is_array($xmlPropertyChild)
+ || 'parameters' !== static::getTagName($xmlPropertyChild['name']))
+ continue;
+
+ $xmlParameters = $xmlPropertyChild['value'];
+
+ foreach ($xmlParameters as $xmlParameter) {
+
+ $propertyParameterValues = [];
+
+ foreach ($xmlParameter['value'] as $xmlParameterValues) {
+ $propertyParameterValues[] = $xmlParameterValues['value'];
+ }
+
+ $propertyParameters[static::getTagName($xmlParameter['name'])]
+ = implode(',', $propertyParameterValues);
+
+ }
+
+ array_splice($xmlProperty['value'], $i, 1);
+
+ }
+
+ $propertyNameExtended = ($this->root instanceof VCalendar
+ ? 'xcal'
+ : 'xcard') . ':' . $propertyName;
+
+ switch ($propertyNameExtended) {
+
+ case 'xcal:geo':
+ $propertyType = 'float';
+ $propertyValue['latitude'] = 0;
+ $propertyValue['longitude'] = 0;
+
+ foreach ($xmlProperty['value'] as $xmlRequestChild) {
+ $propertyValue[static::getTagName($xmlRequestChild['name'])]
+ = $xmlRequestChild['value'];
+ }
+ break;
+
+ case 'xcal:request-status':
+ $propertyType = 'text';
+
+ foreach ($xmlProperty['value'] as $xmlRequestChild) {
+ $propertyValue[static::getTagName($xmlRequestChild['name'])]
+ = $xmlRequestChild['value'];
+ }
+ break;
+
+ case 'xcal:freebusy':
+ $propertyType = 'freebusy';
+ // We don't break because we only want to set
+ // another property type.
+
+ case 'xcal:categories':
+ case 'xcal:resources':
+ case 'xcal:exdate':
+ foreach ($xmlProperty['value'] as $specialChild) {
+ $propertyValue[static::getTagName($specialChild['name'])]
+ = $specialChild['value'];
+ }
+ break;
+
+ case 'xcal:rdate':
+ $propertyType = 'date-time';
+
+ foreach ($xmlProperty['value'] as $specialChild) {
+
+ $tagName = static::getTagName($specialChild['name']);
+
+ if ('period' === $tagName) {
+
+ $propertyParameters['value'] = 'PERIOD';
+ $propertyValue[] = implode('/', $specialChild['value']);
+
+ }
+ else {
+ $propertyValue[] = $specialChild['value'];
+ }
+ }
+ break;
+
+ default:
+ $propertyType = static::getTagName($xmlProperty['value'][0]['name']);
+
+ foreach ($xmlProperty['value'] as $value) {
+ $propertyValue[] = $value['value'];
+ }
+
+ if ('date' === $propertyType) {
+ $propertyParameters['value'] = 'DATE';
+ }
+ break;
+ }
+
+ $this->createProperty(
+ $parentComponent,
+ $propertyNamePrefix . $propertyName,
+ $propertyParameters,
+ $propertyType,
+ $propertyValue
+ );
+
+ }
+
+ }
+
+ /**
+ * Parse a component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseComponent(Component $parentComponent) {
+
+ $components = $this->pointer['value'] ?: [];
+
+ foreach ($components as $component) {
+
+ $componentName = static::getTagName($component['name']);
+ $currentComponent = $this->root->createComponent(
+ $componentName,
+ null,
+ false
+ );
+
+ $this->pointer = &$component;
+ $this->parseVCalendarComponents($currentComponent);
+
+ $parentComponent->add($currentComponent);
+
+ }
+
+ }
+
+ /**
+ * Create a property.
+ *
+ * @param Component $parentComponent
+ * @param string $name
+ * @param array $parameters
+ * @param string $type
+ * @param mixed $value
+ *
+ * @return void
+ */
+ protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value) {
+
+ $property = $this->root->createProperty(
+ $name,
+ null,
+ $parameters,
+ $type
+ );
+ $parentComponent->add($property);
+ $property->setXmlValue($value);
+
+ }
+
+ /**
+ * Sets the input data.
+ *
+ * @param resource|string $input
+ *
+ * @return void
+ */
+ function setInput($input) {
+
+ if (is_resource($input)) {
+ $input = stream_get_contents($input);
+ }
+
+ if (is_string($input)) {
+
+ $reader = new SabreXml\Reader();
+ $reader->elementMap['{' . self::XCAL_NAMESPACE . '}period']
+ = 'Sabre\VObject\Parser\XML\Element\KeyValue';
+ $reader->elementMap['{' . self::XCAL_NAMESPACE . '}recur']
+ = 'Sabre\VObject\Parser\XML\Element\KeyValue';
+ $reader->xml($input);
+ $input = $reader->parse();
+
+ }
+
+ $this->input = $input;
+
+ }
+
+ /**
+ * Get tag name from a Clark notation.
+ *
+ * @param string $clarkedTagName
+ *
+ * @return string
+ */
+ protected static function getTagName($clarkedTagName) {
+
+ list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
+ return $tagName;
+
+ }
+}