Passed
Push — master ( a13bb5...cada17 )
by Ryan
32:56 queued 18:49
created

AbstractXmlMiddleware::generateQuery()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 20
nc 3
nop 2
dl 0
loc 29
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright (c) 2017–2018 Ryan Parman <http://ryanparman.com>.
4
 * Copyright (c) 2017–2018 Contributors.
5
 *
6
 * http://opensource.org/licenses/Apache2.0
7
 */
8
9
declare(strict_types=1);
10
11
namespace SimplePie\Middleware\Xml;
12
13
use SimplePie\Middleware\AbstractMiddleware;
14
use SimplePie\Type\Node;
15
16
/**
17
 * The base XML middleware class that all other XML middleware classes extend from. It handles low-level functionality
18
 * that is shared across all XML middleware classes.
19
 */
20
abstract class AbstractXmlMiddleware extends AbstractMiddleware
21
{
22
    /**
23
     * Replace all instances of `%s` with the `$namespaceAlias` parameter.
24
     *
25
     * This is similar to `sprintf()`, but the `$namespaceAlias` is applied to _all_ instances of `%s`.
26
     *
27
     * @param string $query          An XPath query where `%s` is used in-place of the XML namespace alias.
28
     * @param string $namespaceAlias The XML namespace alias to apply.
29
     *
30
     * @return string
31
     */
32
    public function applyNsToQuery(string $query, string $namespaceAlias): string
33
    {
34
        return \str_replace('%s', $namespaceAlias, $query);
35
    }
36
37
    /**
38
     * Produce an XPath 1.0 expression which is used to query XML document nodes.
39
     *
40
     * ```php
41
     * ['feed', 'entry', 5, 'id']
42
     * ```
43
     *
44
     * ```xpath
45
     * /feed/entry[5]/id (simplified)
46
     * ```
47
     *
48
     * @param string $namespaceAlias The XML namespace alias to apply.
49
     * @param array  $path           An ordered array of nested elements, starting from the top-level XML node.
50
     *                               If an integer is added, then it is assumed that the element before it should be
51
     *                               handled as an array and the integer is its index. Expression is generated
52
     *                               left-to-right.
53
     *
54
     * @return string An XPath 1.0 expression.
55
     */
56
    public function generateQuery(string $namespaceAlias, array $path): string
57
    {
58
        $query = '';
59
60
        while (\count($path)) {
61
            $p    = \array_shift($path);
62
            $next = $path[0] ?? null;
63
64
            if (\is_int($next)) {
65
                $query .= \sprintf(
66
                    '/%s:*[translate(name(), \'%s\', \'%s\') = \'%s\'][position() = %d]',
67
                    $namespaceAlias,
68
                    'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
69
                    'abcdefghijklmnopqrstuvwxyz',
70
                    $p,
71
                    \array_shift($path) + 1
72
                );
73
            } else {
74
                $query .= \sprintf(
75
                    '/%s:*[translate(name(), \'%s\', \'%s\') = \'%s\']',
76
                    $namespaceAlias,
77
                    'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
78
                    'abcdefghijklmnopqrstuvwxyz',
79
                    $p
80
                );
81
            }
82
        }
83
84
        return $query;
85
    }
86
87
    /**
88
     * Some elements in the feed should only have one result. This handles those cases.
89
     *
90
     * @param callable $fn A callable which returns a `DOMElementList`.
91
     *
92
     * @return array Returns an array with keys of `text` and `html`.
93
     */
94
    public function handleSingleNode(callable $fn): Node
95
    {
96
        $nodes = $fn();
97
98
        if ($nodes->length > 0) {
99
            return new Node($nodes[0]);
100
        }
101
102
        return new Node();
103
    }
104
}
105