1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 * A XML lint task. Checking syntax of one or more XML files against an XML Schema using the DOM extension.
22
 *
23
 * @author  Knut Urdalen <knut.urdalen@telio.no>
24
 * @package phing.tasks.ext
25
 */
26
class XmlLintTask extends Task
27
{
28
    use FileSetAware;
29

30
    protected $file; // the source file (from xml attribute)
31
    protected $schema; // the schema file (from xml attribute)
32
    protected $useRNG = false;
33

34
    protected $haltonfailure = true;
35

36
    /**
37
     * File to be performed syntax check on
38
     *
39
     * @param PhingFile $file
40
     */
41 0
    public function setFile(PhingFile $file)
42
    {
43 0
        $this->file = $file;
44
    }
45

46
    /**
47
     * XML Schema Description file to validate against
48
     *
49
     * @param PhingFile $schema
50
     */
51 0
    public function setSchema(PhingFile $schema)
52
    {
53 0
        $this->schema = $schema;
54
    }
55

56
    /**
57
     * Use RNG instead of DTD schema validation
58
     *
59
     * @param bool $bool
60
     */
61 0
    public function setUseRNG($bool)
62
    {
63 0
        $this->useRNG = (bool) $bool;
64
    }
65

66
    /**
67
     * Sets the haltonfailure attribute
68
     *
69
     * @param bool $haltonfailure
70
     *
71
     * @return void
72
     */
73 0
    public function setHaltonfailure(bool $haltonfailure)
74
    {
75 0
        $this->haltonfailure = $haltonfailure;
76
    }
77

78
    /**
79
     * Execute lint check against PhingFile or a FileSet.
80
     *
81
     * {@inheritdoc}
82
     *
83
     * @throws BuildException
84
     *
85
     * @return void
86
     */
87 0
    public function main()
88
    {
89 0
        if (isset($this->schema) && !file_exists($this->schema->getPath())) {
90 0
            throw new BuildException("Schema file not found: " . $this->schema->getPath());
91
        }
92 0
        if (!isset($this->file) and count($this->filesets) == 0) {
93 0
            throw new BuildException("Missing either a nested fileset or attribute 'file' set");
94
        }
95

96 0
        set_error_handler([$this, 'errorHandler']);
97 0
        if ($this->file instanceof PhingFile) {
98 0
            $this->lint($this->file->getPath());
99
        } else { // process filesets
100 0
            $project = $this->getProject();
101 0
            foreach ($this->filesets as $fs) {
102 0
                $ds = $fs->getDirectoryScanner($project);
103 0
                $files = $ds->getIncludedFiles();
104 0
                $dir = $fs->getDir($this->project)->getPath();
105 0
                foreach ($files as $file) {
106 0
                    $this->lint($dir . DIRECTORY_SEPARATOR . $file);
107
                }
108
            }
109
        }
110 0
        restore_error_handler();
111
    }
112

113
    /**
114
     * @param $message
115
     *
116
     * @return void
117
     *
118
     * @throws BuildException
119
     */
120 0
    protected function logError($message)
121
    {
122 0
        if ($this->haltonfailure) {
123 0
            throw new BuildException($message);
124
        }
125

126 0
        $this->log($message, Project::MSG_ERR);
127
    }
128

129
    /**
130
     * Performs validation
131
     *
132
     * @param string $file
133
     *
134
     * @return void
135
     */
136 0
    protected function lint($file)
137
    {
138 0
        if (file_exists($file)) {
139 0
            if (is_readable($file)) {
140 0
                $dom = new DOMDocument();
141 0
                if ($dom->load($file) === false) {
142 0
                    $error = libxml_get_last_error();
143 0
                    $this->logError($file . ' is not well-formed (See messages above)');
144
                } else {
145 0
                    if (isset($this->schema)) {
146 0
                        if ($this->useRNG) {
147 0
                            if ($dom->relaxNGValidate($this->schema->getPath())) {
148 0
                                $this->log($file . ' validated with RNG grammar', Project::MSG_INFO);
149
                            } else {
150 0
                                $this->logError($file . ' fails to validate (See messages above)');
151
                            }
152
                        } else {
153 0
                            if ($dom->schemaValidate($this->schema->getPath())) {
154 0
                                $this->log($file . ' validated with schema', Project::MSG_INFO);
155
                            } else {
156 0
                                $this->logError($file . ' fails to validate (See messages above)');
157
                            }
158
                        }
159
                    } else {
160 0
                        $this->log(
161 0
                            $file . ' is well-formed (not validated due to missing schema specification)',
162 0
                            Project::MSG_INFO
163
                        );
164
                    }
165
                }
166
            } else {
167 0
                $this->logError('Permission denied to read file: ' . $file);
168
            }
169
        } else {
170 0
            $this->logError('File not found: ' . $file);
171
        }
172
    }
173

174
    /**
175
     * Local error handler to catch validation errors and log them through Phing
176
     *
177
     * @param int $level
178
     * @param string $message
179
     * @param string $file
180
     * @param int $line
181
     * @param mixed $context
182
     *
183
     * @return void
184
     */
185 0
    public function errorHandler($level, $message, $file, $line, $context)
186
    {
187 0
        $matches = [];
188 0
        preg_match('/^.*\(\): (.*)$/', $message, $matches);
189 0
        $this->log($matches[1], Project::MSG_ERR);
190
    }
191
}

Read our documentation on viewing source code .

Loading