Completed
Pull Request — master (#18)
by Auke
02:15
created

xml::parse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 6
Bugs 2 Features 3
Metric Value
c 6
b 2
f 3
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
crap 1
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
 * This class contains the parse and css2XPath methods.
16
 * In addition any other method statically called on this class
17
 * will reroute the call to the XML writer instance at 
18
 * \arc\xml::$writer. It is automatically instantiated if needed.
19
 * Or you can set it yourself to another Writer instance.
20
 */
21
class xml
22
{
23
    /**
24
     * @var xml\Writer The writer instance to use by default
25
     */
26
    static $writer = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $writer.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
27
28 3
    public static function __callStatic( $name, $args )
29
    {
30 3
        if ( !isset(self::$writer) ) {
31 1
            self::$writer = new xml\Writer();
32 1
        }
33 3
        return call_user_func_array( [ self::$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 5
        $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 2
    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 1
    {
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 2
            => '\1//\3',
60
            // E > F: Matches any F element that is a child of an element E
61
            '/(\w+)\s*>\s*(\w+)/'
62 2
            => '\1/\2',
63
            // E:first-child: Matches element E when E is the first child of its parent
64
            '/(\w+|\*):first-child/'
65 2
            => '*[1]/self::\1',
66
            // E:checked, E:disabled or E:selected
1 ignored issue
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
67
            '/(\w+|\*):(checked|disabled|selected)/'
68 2
            => '\1 [ @\2 ]',
69
            // E + F: Matches any F element immediately preceded by an element
70
            '/(\w+)\s*\+\s*(\w+)/'
71 2
            => '\1/following-sibling::*[1]/self::\2',
72
            // E ~ F: Matches any F element preceded by an element
73
            '/(\w+)\s*\~\s*(\w+)/'
74 2
            => '\1/following-sibling::*/self::\2',
75
            // E[foo]: Matches any E element with the "foo" attribute set (whatever the value)
76
            '/(\w+)\[([\w\-]+)]/'
77 2
            => '\1 [ @\2 ]',
78
            // E[foo="warning"]: Matches any E element whose "foo" attribute value is exactly equal to "warning"
79
            '/(\w+)\[([\w\-]+)\=\"(.*)\"]/'
80 2
            => '\1[ contains( concat( " ", normalize-space(@\2), " " ), concat( " ", "\3", " " ) ) ]',
81
            // .warning: HTML only. The same as *[class~="warning"]
82
            '/(^|\s)\.([\w\-]+)+/'
83 2
            => '*[ contains( concat( " ", normalize-space(@class), " " ), concat( " ", "\2", " " ) ) ]',
84
            // div.warning: HTML only. The same as DIV[class~="warning"]
85
            '/(\w+|\*)\.([\w\-]+)+/'
86 2
            => '\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 2
            => '\1[ @id = "\2" ]',
90
            // #myid: Matches any E element with id-attribute equal to "myid"
91
            '/\#([\w\-]+)/'
92
            => '*[ @id = "\1" ]'
93 2
        );
94
95 2
        $cssSelectors = array_keys($translateList);
96 2
        $xPathQueries = array_values($translateList);
97
        do {
98 2
            $continue    = false;
99 2
            $cssSelector = (string) preg_replace($cssSelectors, $xPathQueries, $cssSelector);
100 2
            foreach ( $cssSelectors as $selector ) {
101 2
                if ( preg_match($selector, $cssSelector) ) {
102 1
                    $continue = true;
103 1
                    break;
104
                }
105 2
            }
106 2
        } while ( $continue );
107 2
        return '//'.$cssSelector;
108
    }
109
}
110