1: <?php
2: /**
3: * Handles parsing the provided XML input.
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 2.1
11: * @link http://www.horde.org/libraries/Horde_Kolab_Format
12: */
13:
14: /**
15: * Handles parsing the provided XML input.
16: *
17: * Copyright 2007-2009 Klarälvdalens Datakonsult AB
18: * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
19: *
20: * See the enclosed file COPYING for license information (LGPL). If you did not
21: * receive this file, see
22: * http://www.horde.org/licenses/lgpl21.
23: *
24: * @category Kolab
25: * @package Kolab_Format
26: * @author Gunnar Wrobel <wrobel@pardus.de>
27: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
28: * @link http://www.horde.org/libraries/Horde_Kolab_Format
29: */
30: class Horde_Kolab_Format_Xml_Parser
31: {
32: /**
33: * The XML parser.
34: *
35: * @var DOMDocument
36: */
37: private $_document;
38:
39: /**
40: * Constructor.
41: *
42: * @param DOMDocument $document The XML parser.
43: */
44: public function __construct(DOMDocument $document)
45: {
46: $this->_document = $document;
47: $this->_document->preserveWhiteSpace = false;
48: $this->_document->formatOutput = true;
49: }
50:
51: /**
52: * Simply return the DOMDocument without parsing any data.
53: *
54: * @since Horde_Kolab_Format 1.1.0
55: *
56: * @return DOMDocument The DOM document.
57: */
58: public function getDocument()
59: {
60: return $this->_document;
61: }
62:
63: /**
64: * Load an object based on the given XML string.
65: *
66: * @param string $input The XML of the message as string.
67: * @param array $options Additional options when parsing the XML.
68: * <pre>
69: * - relaxed: Relaxed error checking (default: false)
70: * </pre>
71: *
72: * @return DOMDocument The DOM document.
73: *
74: * @throws Horde_Kolab_Format_Exception If parsing the XML data failed.
75: */
76: public function parse($input, $options = array())
77: {
78: if (is_resource($input)) {
79: rewind($input);
80: $input = stream_get_contents($input);
81: }
82: try {
83: return $this->_parseXml($input, $options);
84: } catch (Horde_Kolab_Format_Exception_ParseError $e) {
85: if (!function_exists('mb_detect_encoding')) {
86: throw $e;
87: }
88: /**
89: * If the first call does not return successfully this might mean we
90: * got an attachment with broken encoding. There are some Kolab
91: * client versions in the wild that might have done that. So the
92: * next section starts a second attempt by guessing the encoding and
93: * trying again.
94: */
95: if (0 !== strcasecmp(
96: mb_detect_encoding($input, 'UTF-8, ISO-8859-1'), 'UTF-8'
97: )) {
98: $input = mb_convert_encoding($input, 'UTF-8', 'ISO-8859-1');
99: }
100: return $this->_parseXml($input, $options);
101: }
102: }
103:
104: /**
105: * Parse the XML string. The root node is returned on success.
106: *
107: * @param string $input The XML of the message as string.
108: * @param array $options Additional options when parsing the XML.
109: *
110: * @return DOMDocument The DOM document.
111: *
112: * @throws Horde_Kolab_Format_Exception If parsing the XML data failed.
113: */
114: private function _parseXml($input, $options = array())
115: {
116: $result = @$this->_document->loadXML($input);
117: if (!empty($options['relaxed'])) {
118: return $this->_document;
119: }
120: if (!$result) {
121: throw new Horde_Kolab_Format_Exception_ParseError($input);
122: }
123: if (empty($this->_document->documentElement)) {
124: throw new Horde_Kolab_Format_Exception_ParseError($input);
125: }
126: if (!$this->_document->documentElement->hasChildNodes()) {
127: throw new Horde_Kolab_Format_Exception_ParseError($input);
128: }
129: return $this->_document;
130: }
131: }
132: