Subversion Repositories web.creative

Rev

Details | Last modification | View Log

Rev Author Line No. Line
1 mjordaan 1
<?php
2
/*
3
 * This file is part of PHPUnit.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
 
11
/**
12
 * XML helpers.
13
 */
14
class PHPUnit_Util_XML
15
{
16
    /**
17
     * Load an $actual document into a DOMDocument.  This is called
18
     * from the selector assertions.
19
     *
20
     * If $actual is already a DOMDocument, it is returned with
21
     * no changes.  Otherwise, $actual is loaded into a new DOMDocument
22
     * as either HTML or XML, depending on the value of $isHtml. If $isHtml is
23
     * false and $xinclude is true, xinclude is performed on the loaded
24
     * DOMDocument.
25
     *
26
     * Note: prior to PHPUnit 3.3.0, this method loaded a file and
27
     * not a string as it currently does.  To load a file into a
28
     * DOMDocument, use loadFile() instead.
29
     *
30
     * @param string|DOMDocument $actual
31
     * @param bool               $isHtml
32
     * @param string             $filename
33
     * @param bool               $xinclude
34
     * @param bool               $strict
35
     *
36
     * @return DOMDocument
37
     */
38
    public static function load($actual, $isHtml = false, $filename = '', $xinclude = false, $strict = false)
39
    {
40
        if ($actual instanceof DOMDocument) {
41
            return $actual;
42
        }
43
 
44
        if (!is_string($actual)) {
45
            throw new PHPUnit_Framework_Exception('Could not load XML from ' . gettype($actual));
46
        }
47
 
48
        if ($actual === '') {
49
            throw new PHPUnit_Framework_Exception('Could not load XML from empty string');
50
        }
51
 
52
        // Required for XInclude on Windows.
53
        if ($xinclude) {
54
            $cwd = getcwd();
55
            @chdir(dirname($filename));
56
        }
57
 
58
        $document                     = new DOMDocument;
59
        $document->preserveWhiteSpace = false;
60
 
61
        $internal  = libxml_use_internal_errors(true);
62
        $message   = '';
63
        $reporting = error_reporting(0);
64
 
65
        if ('' !== $filename) {
66
            // Necessary for xinclude
67
            $document->documentURI = $filename;
68
        }
69
 
70
        if ($isHtml) {
71
            $loaded = $document->loadHTML($actual);
72
        } else {
73
            $loaded = $document->loadXML($actual);
74
        }
75
 
76
        if (!$isHtml && $xinclude) {
77
            $document->xinclude();
78
        }
79
 
80
        foreach (libxml_get_errors() as $error) {
81
            $message .= "\n" . $error->message;
82
        }
83
 
84
        libxml_use_internal_errors($internal);
85
        error_reporting($reporting);
86
 
87
        if ($xinclude) {
88
            @chdir($cwd);
89
        }
90
 
91
        if ($loaded === false || ($strict && $message !== '')) {
92
            if ($filename !== '') {
93
                throw new PHPUnit_Framework_Exception(
94
                    sprintf(
95
                        'Could not load "%s".%s',
96
                        $filename,
97
                        $message != '' ? "\n" . $message : ''
98
                    )
99
                );
100
            } else {
101
                if ($message === '') {
102
                    $message = 'Could not load XML for unknown reason';
103
                }
104
                throw new PHPUnit_Framework_Exception($message);
105
            }
106
        }
107
 
108
        return $document;
109
    }
110
 
111
    /**
112
     * Loads an XML (or HTML) file into a DOMDocument object.
113
     *
114
     * @param string $filename
115
     * @param bool   $isHtml
116
     * @param bool   $xinclude
117
     * @param bool   $strict
118
     *
119
     * @return DOMDocument
120
     */
121
    public static function loadFile($filename, $isHtml = false, $xinclude = false, $strict = false)
122
    {
123
        $reporting = error_reporting(0);
124
        $contents  = file_get_contents($filename);
125
        error_reporting($reporting);
126
 
127
        if ($contents === false) {
128
            throw new PHPUnit_Framework_Exception(
129
                sprintf(
130
                    'Could not read "%s".',
131
                    $filename
132
                )
133
            );
134
        }
135
 
136
        return self::load($contents, $isHtml, $filename, $xinclude, $strict);
137
    }
138
 
139
    /**
140
     * @param DOMNode $node
141
     */
142
    public static function removeCharacterDataNodes(DOMNode $node)
143
    {
144
        if ($node->hasChildNodes()) {
145
            for ($i = $node->childNodes->length - 1; $i >= 0; $i--) {
146
                if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) {
147
                    $node->removeChild($child);
148
                }
149
            }
150
        }
151
    }
152
 
153
    /**
154
     * Escapes a string for the use in XML documents
155
     * Any Unicode character is allowed, excluding the surrogate blocks, FFFE,
156
     * and FFFF (not even as character reference).
157
     * See http://www.w3.org/TR/xml/#charsets
158
     *
159
     * @param string $string
160
     *
161
     * @return string
162
     */
163
    public static function prepareString($string)
164
    {
165
        return preg_replace(
166
            '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/',
167
            '',
168
            htmlspecialchars(
169
                PHPUnit_Util_String::convertToUtf8($string),
170
                ENT_QUOTES,
171
                'UTF-8'
172
            )
173
        );
174
    }
175
 
176
    /**
177
     * "Convert" a DOMElement object into a PHP variable.
178
     *
179
     * @param DOMElement $element
180
     *
181
     * @return mixed
182
     */
183
    public static function xmlToVariable(DOMElement $element)
184
    {
185
        $variable = null;
186
 
187
        switch ($element->tagName) {
188
            case 'array':
189
                $variable = [];
190
 
191
                foreach ($element->childNodes as $entry) {
192
                    if (!$entry instanceof DOMElement || $entry->tagName !== 'element') {
193
                        continue;
194
                    }
195
                    $item = $entry->childNodes->item(0);
196
 
197
                    if ($item instanceof DOMText) {
198
                        $item = $entry->childNodes->item(1);
199
                    }
200
 
201
                    $value = self::xmlToVariable($item);
202
 
203
                    if ($entry->hasAttribute('key')) {
204
                        $variable[(string) $entry->getAttribute('key')] = $value;
205
                    } else {
206
                        $variable[] = $value;
207
                    }
208
                }
209
                break;
210
 
211
            case 'object':
212
                $className = $element->getAttribute('class');
213
 
214
                if ($element->hasChildNodes()) {
215
                    $arguments       = $element->childNodes->item(1)->childNodes;
216
                    $constructorArgs = [];
217
 
218
                    foreach ($arguments as $argument) {
219
                        if ($argument instanceof DOMElement) {
220
                            $constructorArgs[] = self::xmlToVariable($argument);
221
                        }
222
                    }
223
 
224
                    $class    = new ReflectionClass($className);
225
                    $variable = $class->newInstanceArgs($constructorArgs);
226
                } else {
227
                    $variable = new $className;
228
                }
229
                break;
230
 
231
            case 'boolean':
232
                $variable = $element->textContent == 'true' ? true : false;
233
                break;
234
 
235
            case 'integer':
236
            case 'double':
237
            case 'string':
238
                $variable = $element->textContent;
239
 
240
                settype($variable, $element->tagName);
241
                break;
242
        }
243
 
244
        return $variable;
245
    }
246
}