1<?php
2
3namespace Sabre\Xml\Element;
4
5use Sabre\Xml;
6
7/**
8 * 'KeyValue' parses out all child elements from a single node, and outputs a
9 * key=>value struct.
10 *
11 * Attributes will be removed, and duplicate child elements are discarded.
12 * Complex values within the elements will be parsed by the 'standard' parser.
13 *
14 * For example, KeyValue will parse:
15 *
16 * <?xml version="1.0"?>
17 * <s:root xmlns:s="http://sabredav.org/ns">
18 *   <s:elem1>value1</s:elem1>
19 *   <s:elem2>value2</s:elem2>
20 *   <s:elem3 />
21 * </s:root>
22 *
23 * Into:
24 *
25 * [
26 *   "{http://sabredav.org/ns}elem1" => "value1",
27 *   "{http://sabredav.org/ns}elem2" => "value2",
28 *   "{http://sabredav.org/ns}elem3" => null,
29 * ];
30 *
31 * @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
32 * @author Evert Pot (http://evertpot.com/)
33 * @license http://sabre.io/license/ Modified BSD License
34 */
35class KeyValue implements Xml\Element {
36
37    /**
38     * Value to serialize
39     *
40     * @var array
41     */
42    protected $value;
43
44    /**
45     * Constructor
46     *
47     * @param array $value
48     */
49    function __construct(array $value = []) {
50
51        $this->value = $value;
52
53    }
54
55    /**
56     * The xmlSerialize metod is called during xml writing.
57     *
58     * Use the $writer argument to write its own xml serialization.
59     *
60     * An important note: do _not_ create a parent element. Any element
61     * implementing XmlSerializble should only ever write what's considered
62     * its 'inner xml'.
63     *
64     * The parent of the current element is responsible for writing a
65     * containing element.
66     *
67     * This allows serializers to be re-used for different element names.
68     *
69     * If you are opening new elements, you must also close them again.
70     *
71     * @param Writer $writer
72     * @return void
73     */
74    function xmlSerialize(Xml\Writer $writer) {
75
76        $writer->write($this->value);
77
78    }
79
80    /**
81     * The deserialize method is called during xml parsing.
82     *
83     * This method is called staticly, this is because in theory this method
84     * may be used as a type of constructor, or factory method.
85     *
86     * Often you want to return an instance of the current class, but you are
87     * free to return other data as well.
88     *
89     * Important note 2: You are responsible for advancing the reader to the
90     * next element. Not doing anything will result in a never-ending loop.
91     *
92     * If you just want to skip parsing for this element altogether, you can
93     * just call $reader->next();
94     *
95     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
96     * the next element.
97     *
98     * @param Xml\Reader $reader
99     * @return mixed
100     */
101    static function xmlDeserialize(Xml\Reader $reader) {
102
103        // If there's no children, we don't do anything.
104        if ($reader->isEmptyElement) {
105            $reader->next();
106            return [];
107        }
108
109        $values = [];
110
111        $reader->read();
112        do {
113
114            if ($reader->nodeType === Xml\Reader::ELEMENT) {
115
116                $clark = $reader->getClark();
117                $values[$clark] = $reader->parseCurrentElement()['value'];
118
119            } else {
120                $reader->read();
121            }
122
123        } while ($reader->nodeType !== Xml\Reader::END_ELEMENT);
124
125        $reader->read();
126
127        return $values;
128
129    }
130
131}
132