1: <?php
2: /**
3: * Provides DOM utility methods.
4: *
5: * PHP version 5
6: *
7: * @category Kolab
8: * @package Kolab_Format
9: * @author Gunnar Wrobel <wrobel@pardus.de>
10: * @license http://www.horde.org/licenses/lgpl21 LGPL
11: * @link http://www.horde.org/libraries/Horde_Kolab_Format
12: */
13:
14: /**
15: * Provides DOM utility methods.
16: *
17: * Copyright 2011-2012 Horde LLC (http://www.horde.org/)
18: *
19: * See the enclosed file COPYING for license information (LGPL). If you did not
20: * receive this file, see
21: * http://www.horde.org/licenses/lgpl21.
22: *
23: * @since Horde_Kolab_Format 1.1.0
24: *
25: * @category Kolab
26: * @package Kolab_Format
27: * @author Gunnar Wrobel <wrobel@pardus.de>
28: * @license http://www.horde.org/licenses/lgpl21 LGPL
29: * @link http://www.horde.org/libraries/Horde_Kolab_Format
30: */
31: class Horde_Kolab_Format_Xml_Helper
32: {
33: /**
34: * The XML document this object works with.
35: *
36: * @var DOMDocument
37: */
38: protected $_xmldoc;
39:
40: /**
41: * The XPath query handler.
42: *
43: * @var DOMXpath
44: */
45: private $_xpath;
46:
47: /**
48: * Constructor
49: *
50: * @param DOMDocument $xmldoc The XML document this object works with.
51: */
52: public function __construct($xmldoc)
53: {
54: $this->_xmldoc = $xmldoc;
55: $this->_xpath = new DOMXpath($this->_xmldoc);
56: }
57:
58: /**
59: * Fetch the value of a node.
60: *
61: * @param DOMNode $node Retrieve the text value for this node.
62: *
63: * @return string|null The text value or null if no value was identified.
64: */
65: public function fetchNodeValue($node)
66: {
67: if (($child = $this->_fetchFirstTextNode($node)) !== null) {
68: return $child->nodeValue;
69: }
70: return null;
71: }
72:
73: /**
74: * Fetch the the first text node.
75: *
76: * @param DOMNode $node Retrieve the text value for this node.
77: *
78: * @return DOMNode|null The first text node or null if no such node was
79: * found.
80: */
81: private function _fetchFirstTextNode($node)
82: {
83: foreach ($node->childNodes as $child) {
84: if ($child->nodeType === XML_TEXT_NODE) {
85: return $child;
86: }
87: }
88: }
89:
90: /**
91: * Store a value as a new text node.
92: *
93: * @param DOMNode $parent_node Attach the new node to this parent.
94: * @param string $name Name of the new child node.
95: * @param string $value Text value of the new child node.
96: *
97: * @return DOMNode The new child node.
98: */
99: public function storeNewNodeValue($parent_node, $name, $value)
100: {
101: $node = $this->createNewNode($parent_node, $name);
102: $this->createNodeValue($node, $name, $value);
103: return $node;
104: }
105:
106: /**
107: * Store a value as a new text node.
108: *
109: * @param DOMNode $parent_node Attach the new node to this parent.
110: * @param string $name Name of the new child node.
111: * @param string $value Text value of the new child node.
112: *
113: * @return DOMNode The new child node.
114: */
115: public function createNodeValue($parent_node, $name, $value)
116: {
117: $node = $this->_xmldoc->createTextNode($value);
118: $parent_node->appendChild($node);
119: return $node;
120: }
121:
122: /**
123: * Append an XML snippet.
124: *
125: * @param DOMNode $parent_node Attach the XML below this parent.
126: * @param string $xml The XML to append.
127: *
128: * @return DOMNode The new child node.
129: */
130: public function appendXml($parent_node, $xml)
131: {
132: $node = $this->_xmldoc->createDocumentFragment();
133: $node->appendXML($xml);
134: $parent_node->appendChild($node);
135: return $node;
136: }
137:
138: /**
139: * Create a new node.
140: *
141: * @param DOMNode $parent_node Attach the new node to this parent.
142: * @param string $name Name of the new child node.
143: *
144: * @return DOMNode The new child node.
145: */
146: public function createNewNode($parent_node, $name)
147: {
148: $node = $this->_xmldoc->createElement($name);
149: $parent_node->appendChild($node);
150: return $node;
151: }
152:
153: /**
154: * Store a value as a new text node.
155: *
156: * @param DOMNode $node Replace the text value of this node.
157: * @param string $value Text value of the new child node.
158: *
159: * @return NULL
160: */
161: public function replaceFirstNodeTextValue($node, $value)
162: {
163: if (($child = $this->_fetchFirstTextNode($node)) !== null) {
164: $node->removeChild($child);
165: }
166: $new_node = $this->_xmldoc->createTextNode($value);
167: if (empty($node->childNodes)) {
168: $node->appendChild($new_node);
169: } else {
170: $node->insertBefore($new_node, $node->childNodes->item(0));
171: }
172: }
173:
174: /**
175: * Return a single named node matching the given XPath query.
176: *
177: * @param string $query The query.
178: *
179: * @return DOMNode|false The named DOMNode or empty if no node was found.
180: */
181: public function findNode($query)
182: {
183: $result = $this->_xpath->query($query);
184: if ($result->length) {
185: return $result->item(0);
186: }
187: return false;
188: }
189:
190: /**
191: * Return a single named node below the given context matching the given
192: * XPath query.
193: *
194: * @param string $query The query.
195: * @param DOMNode $context Search below this node.
196: *
197: * @return DOMNode|false The named DOMNode or empty if no node was found.
198: */
199: public function findNodeRelativeTo($query, DOMNode $context)
200: {
201: $result = $this->_xpath->query($query, $context);
202: if ($result->length) {
203: return $result->item(0);
204: }
205: return false;
206: }
207:
208: /**
209: * Return all nodes matching the given XPath query.
210: *
211: * @param string $query The query.
212: *
213: * @return DOMNodeList The list of DOMNodes.
214: */
215: public function findNodes($query)
216: {
217: return $this->_xpath->query($query);
218: }
219:
220: /**
221: * Return all nodes matching the given XPath query.
222: *
223: * @param string $query The query.
224: * @param DOMNode $context Search below this node.
225: *
226: * @return DOMNodeList The list of DOMNodes.
227: */
228: public function findNodesRelativeTo($query, DOMNode $context)
229: {
230: return $this->_xpath->query($query, $context);
231: }
232:
233: /**
234: * Remove named nodes from a parent node.
235: *
236: * @param DOMNode $parent_node The parent node.
237: * @param string $name The name of the children to be removed.
238: *
239: * @return NULL
240: */
241: public function removeNodes($parent_node, $name)
242: {
243: foreach ($this->findNodesRelativeTo('./' . $name, $parent_node) as $child) {
244: $parent_node->removeChild($child);
245: }
246: }
247:
248: /**
249: * Output the document as XML string.
250: *
251: * @return string The XML output.
252: */
253: public function __toString()
254: {
255: return $this->_xmldoc->saveXML();
256: }
257: }