Completed
Push — master ( 2edd85...fdf780 )
by Auke
01:57
created

xml::preamble()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 9.5384

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 7
cts 13
cp 0.5385
rs 8.8571
cc 6
eloc 14
nc 10
nop 3
crap 9.5384
1
<?php
2
3
/*
4
 * This file is part of the Ariadne Component Library.
5
 *
6
 * (c) Muze <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace arc;
13
14
/**
15
 * Any method statically called on this class
16
 * will reroute the call to the XML writer instance at 
17
 * \arc\xml::$writer. Except for the methods:
18
 * parse, css2XPath, name, value, attribute, comment, cdata and preamble
19
 * If you need those call the Writer instance directly
20
 */
21
class xml
22
{
23
    /**
24
     * @var xml\Writer The writer instance to use by default
25
     */
26
    public static $writer = null;
27
28 2
    public static function __callStatic( $name, $args )
29
    {
30 2
        if ( !isset(static::$writer) ) {
31 1
            static::$writer = new xml\Writer();
32
        }
33 2
        return call_user_func_array( [ static::$writer, $name ], $args );
34
    }
35
36
    /**
37
     * This parses an XML string and returns a Proxy
38
     * @param string|Proxy $xml
39
     * @return Proxy
40
     * @throws \arc\Exception
41
     */
42 6
    public static function parse( $xml=null, $encoding = null )
43
    {
44 6
        $parser = new xml\Parser();
45 6
        return $parser->parse( $xml, $encoding );
46
    }
47
48
    /**
49
     * This method turns a single CSS 2 selector into an XPath query
50
     * @param string $cssSelector
51
     * @return string
52
     */
53 3
    public static function css2XPath( $cssSelector )
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
54
    {
55
        /* based on work by Tijs Verkoyen - http://blog.verkoyen.eu/blog/p/detail/css-selector-to-xpath-query/ */
56
        $translateList = array(
57
            // E F: Matches any F element that is a descendant of an E element
58
            '/(\w+)\s+(?=([^"]*"[^"]*")*[^"]*$)(\w+)/'
59 3
            => '\1//\3',
60
            // E > F: Matches any F element that is a child of an element E
61
            '/(\w+)\s*>\s*(\w+)/'
62
            => '\1/\2',
63
            // E:first-child: Matches element E when E is the first child of its parent
64
            '/(\w+|\*):first-child/'
65
            => '*[1]/self::\1',
66
            // Matches E:checked, E:disabled or E:selected (and just for scrutinizer: this is not code!)
67
            '/(\w+|\*):(checked|disabled|selected)/'
68
            => '\1 [ @\2 ]',
69
            // E + F: Matches any F element immediately preceded by an element
70
            '/(\w+)\s*\+\s*(\w+)/'
71
            => '\1/following-sibling::*[1]/self::\2',
72
            // E ~ F: Matches any F element preceded by an element
73
            '/(\w+)\s*\~\s*(\w+)/'
74
            => '\1/following-sibling::*/self::\2',
75
            // E[foo]: Matches any E element with the "foo" attribute set (whatever the value)
76
            '/(\w+)\[([\w\-]+)]/'
77
            => '\1 [ @\2 ]',
78
            // E[foo="warning"]: Matches any E element whose "foo" attribute value is exactly equal to "warning"
79
            '/(\w+)\[([\w\-]+)\=\"(.*)\"]/'
80
            => '\1[ contains( concat( " ", normalize-space(@\2), " " ), concat( " ", "\3", " " ) ) ]',
81
            // .warning: HTML only. The same as *[class~="warning"]
82
            '/(^|\s)\.([\w\-]+)+/'
83
            => '*[ contains( concat( " ", normalize-space(@class), " " ), concat( " ", "\2", " " ) ) ]',
84
            // div.warning: HTML only. The same as DIV[class~="warning"]
85
            '/(\w+|\*)\.([\w\-]+)+/'
86
            => '\1[ contains( concat( " ", normalize-space(@class), " " ), concat( " ", "\2", " " ) ) ]',
87
            // E#myid: Matches any E element with id-attribute equal to "myid"
88
            '/(\w+)+\#([\w\-]+)/'
89
            => "\\1[@id='\\2']",
90
            // #myid: Matches any E element with id-attribute equal to "myid"
91
            '/\#([\w\-]+)/'
92
            => "*[@id='\\1']"
93
        );
94
95 3
        $cssSelectors = array_keys($translateList);
96 3
        $xPathQueries = array_values($translateList);
97
        do {
98 3
            $continue    = false;
99 3
            $cssSelector = (string) preg_replace($cssSelectors, $xPathQueries, $cssSelector);
100 3
            foreach ( $cssSelectors as $selector ) {
101 3
                if ( preg_match($selector, $cssSelector) ) {
102 1
                    $continue = true;
103 3
                    break;
104
                }
105
            }
106 3
        } while ( $continue );
107 3
        return '//'.$cssSelector;
108
    }
109
110
    /**
111
     * Returns a guaranteed valid XML name. Removes illegal characters from the name.
112
     * @param string $name
113
     * @return string
114
     */
115 2
    public static function name( $name)
116
    {
117 2
        return preg_replace( '/^[^:a-z_]*/isU', '',
118 2
            preg_replace( '/[^-.0-9:a-z_]/isU', '', $name
119
        ) );
120
    }
121
122
    /**
123
     * Returns a guaranteed valid XML attribute value. Removes illegal characters.
124
     * @param string|array|bool $value
125
     * @return string
126
     */
127 3
    public static function value( $value)
128
    {
129 3
        if (is_array( $value )) {
130
            $content = array_reduce( $value, function( $result, $value)
131
            {
132
                return $result . ' ' . static::value( $value );
133
            } );
134 3
        } else if (is_bool( $value )) {
135
            $content = $value ? 'true' : 'false';
136
        } else {
137 3
            $value = (string) $value;
138 3
            if (preg_match( '/^\s*<!\[CDATA\[/', $value )) {
139
                $content = $value;
140
            } else {
141 3
                $content = htmlspecialchars( (string) $value, ENT_QUOTES, 'UTF-8' );
142
            }
143
        }
144 3
        return $content;
145
    }
146
147
    /**
148
     * Returns a guaranteed valid XML attribute. Removes illegal characters.
149
     * @param string $name
150
     * @param string|array|bool $value
151
     * @return string
152
     */
153 2
    public static function attribute( $name, $value)
154
    {
155 2
        return ' ' . static::name( $name ) . '="' . static::value( $value ) . '"';
156
    }
157
158
    /**
159
     * Returns a guaranteed valid XML comment. Removes illegal characters.
160
     * @param string $content
161
     * @return string
162
     */
163 1
    public static function comment( $content)
164
    {
165 1
        return '<!-- ' . static::value( $content ) . ' -->';
166
    }
167
168
    /**
169
     * Returns a guaranteed valid XML CDATA string. Removes illegal characters.
170
     * @param string $content
171
     * @return string
172
     */
173 1
    public static function cdata( $content)
174
    {
175 1
        return '<![CDATA[' . str_replace( ']]>', ']]&gt;', $content ) . ']]>';
176
    }
177
178
    /**
179
     * Returns an XML preamble.
180
     * @param string $version Defaults to '1.0'
181
     * @param string $encoding Defaults to null
182
     * @param string $standalone Defaults to null
183
     * @return string
184
     */
185 1
    public static function preamble( $version = '1.0', $encoding = null, $standalone = null)
186
    {
187 1
        if (isset($standalone)) {
188
            if ($standalone === 'false') {
189
                $standalone = 'no';
190
            } else if ($standalone !== 'no') {
191
                $standalone = ( $standalone ? 'yes' : 'no' );
192
            }
193
            $standalone = static::attribute( 'standalone', $standalone );
194
        } else {
195 1
            $standalone = '';
196
        }
197 1
        $preamble = '<?xml version="' . static::value($version) . '"';
198 1
        if (isset( $encoding )) {
199
            $preamble .= ' " encoding="' . static::value($encoding) . '"';
200
        }
201 1
        $preamble .= $standalone . ' ?>';
202 1
        return $preamble;
203
    }
204
205
}