1<?php
2
3/**
4 * A linter which uses [[http://php.net/simplexml | SimpleXML]] to detect
5 * errors and potential problems in XML files.
6 */
7final class ArcanistXMLLinter extends ArcanistLinter {
8
9  public function getInfoName() {
10    return pht('SimpleXML Linter');
11  }
12
13  public function getInfoDescription() {
14    return pht('Uses SimpleXML to detect formatting errors in XML files.');
15  }
16
17  public function getLinterName() {
18    return 'XML';
19  }
20
21  public function getLinterConfigurationName() {
22    return 'xml';
23  }
24
25  public function canRun() {
26    return extension_loaded('libxml') && extension_loaded('simplexml');
27  }
28
29  public function getCacheVersion() {
30    return LIBXML_VERSION;
31  }
32
33  public function lintPath($path) {
34    libxml_use_internal_errors(true);
35    libxml_clear_errors();
36
37    if (simplexml_load_string($this->getData($path))) {
38      // XML appears to be valid.
39      return;
40    }
41
42    foreach (libxml_get_errors() as $error) {
43      $message = id(new ArcanistLintMessage())
44        ->setPath($path)
45        ->setLine($error->line)
46        ->setChar($error->column ? $error->column : null)
47        ->setCode($this->getLintMessageFullCode($error->code))
48        ->setName(pht('LibXML Error'))
49        ->setDescription(trim($error->message));
50
51      switch ($error->level) {
52        case LIBXML_ERR_NONE:
53          $message->setSeverity(ArcanistLintSeverity::SEVERITY_DISABLED);
54          break;
55
56        case LIBXML_ERR_WARNING:
57          $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
58          break;
59
60        case LIBXML_ERR_ERROR:
61        case LIBXML_ERR_FATAL:
62          $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
63          break;
64
65        default:
66          $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
67          break;
68      }
69
70      $this->addLintMessage($message);
71    }
72  }
73
74}
75