value" array. * * For example, keyvalue will parse: * * * * value1 * value2 * * * * 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. * * * @param Reader $reader * @param string $namespace * @return array */ function keyValue(Reader $reader, $namespace = null) { // 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->nodeType === Reader::ELEMENT) { if ($namespace !== null && $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->nodeType !== Reader::END_ELEMENT); $reader->read(); return $values; } /** * The 'enum' deserializer parses elements into a simple list * without values or attributes. * * For example, Elements will parse: * * * * * * * content * * * * 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", * ]; * * @param Reader $reader * @param string $namespace * @return string[] */ function enum(Reader $reader, $namespace = null) { // 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->nodeType !== Reader::ELEMENT) { continue; } if (!is_null($namespace) && $namespace === $reader->namespaceURI) { $values[] = $reader->localName; } else { $values[] = $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. * * @param Reader $reader * @param string $className * @param string $namespace * @return object */ function valueObject(Reader $reader, $className, $namespace) { $valueObject = new $className(); if ($reader->isEmptyElement) { $reader->next(); return $valueObject; } $defaultProperties = get_class_vars($className); $reader->read(); do { if ($reader->nodeType === Reader::ELEMENT && $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(); } } else { if (!$reader->read()) { break; } } } while ($reader->nodeType !== Reader::END_ELEMENT); $reader->read(); return $valueObject; } /** * This deserializer helps you deserialize xml structures that look like * this: * * * ... * ... * ... * * * 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. * * @param Reader $reader * @param string $childElementName Element name in clark-notation * @return array */ function repeatingElements(Reader $reader, $childElementName) { if ($childElementName[0] !== '{') { $childElementName = '{}' . $childElementName; } $result = []; foreach ($reader->parseGetElements() as $element) { if ($element['name'] === $childElementName) { $result[] = $element['value']; } } return $result; }