diff options
Diffstat (limited to 'vendor/sabre/vobject/lib/Parser/XML.php')
-rw-r--r-- | vendor/sabre/vobject/lib/Parser/XML.php | 428 |
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; + + } +} |