0
|
1 <?php
|
|
2
|
|
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
|
4
|
|
5 /**
|
|
6 * This file is part of the PEAR Console_CommandLine package.
|
|
7 *
|
|
8 * PHP version 5
|
|
9 *
|
|
10 * LICENSE: This source file is subject to the MIT license that is available
|
|
11 * through the world-wide-web at the following URI:
|
|
12 * http://opensource.org/licenses/mit-license.php
|
|
13 *
|
|
14 * @category Console
|
|
15 * @package Console_CommandLine
|
|
16 * @author David JEAN LOUIS <izimobil@gmail.com>
|
|
17 * @copyright 2007 David JEAN LOUIS
|
|
18 * @license http://opensource.org/licenses/mit-license.php MIT License
|
|
19 * @version CVS: $Id$
|
|
20 * @link http://pear.php.net/package/Console_CommandLine
|
|
21 * @since File available since release 0.1.0
|
|
22 * @filesource
|
|
23 */
|
|
24
|
|
25 /**
|
|
26 * Required file
|
|
27 */
|
|
28 require_once 'Console/CommandLine.php';
|
|
29
|
|
30 /**
|
|
31 * Parser for command line xml definitions.
|
|
32 *
|
|
33 * @category Console
|
|
34 * @package Console_CommandLine
|
|
35 * @author David JEAN LOUIS <izimobil@gmail.com>
|
|
36 * @copyright 2007 David JEAN LOUIS
|
|
37 * @license http://opensource.org/licenses/mit-license.php MIT License
|
|
38 * @version Release: @package_version@
|
|
39 * @link http://pear.php.net/package/Console_CommandLine
|
|
40 * @since Class available since release 0.1.0
|
|
41 */
|
|
42 class Console_CommandLine_XmlParser
|
|
43 {
|
|
44 // parse() {{{
|
|
45
|
|
46 /**
|
|
47 * Parses the given xml definition file and returns a
|
|
48 * Console_CommandLine instance constructed with the xml data.
|
|
49 *
|
|
50 * @param string $xmlfile The xml file to parse
|
|
51 *
|
|
52 * @return Console_CommandLine A parser instance
|
|
53 */
|
|
54 public static function parse($xmlfile)
|
|
55 {
|
|
56 if (!is_readable($xmlfile)) {
|
|
57 Console_CommandLine::triggerError('invalid_xml_file',
|
|
58 E_USER_ERROR, array('{$file}' => $xmlfile));
|
|
59 }
|
|
60 $doc = new DomDocument();
|
|
61 $doc->load($xmlfile);
|
|
62 self::validate($doc);
|
|
63 $nodes = $doc->getElementsByTagName('command');
|
|
64 $root = $nodes->item(0);
|
|
65 return self::_parseCommandNode($root, true);
|
|
66 }
|
|
67
|
|
68 // }}}
|
|
69 // parseString() {{{
|
|
70
|
|
71 /**
|
|
72 * Parses the given xml definition string and returns a
|
|
73 * Console_CommandLine instance constructed with the xml data.
|
|
74 *
|
|
75 * @param string $xmlstr The xml string to parse
|
|
76 *
|
|
77 * @return Console_CommandLine A parser instance
|
|
78 */
|
|
79 public static function parseString($xmlstr)
|
|
80 {
|
|
81 $doc = new DomDocument();
|
|
82 $doc->loadXml($xmlstr);
|
|
83 self::validate($doc);
|
|
84 $nodes = $doc->getElementsByTagName('command');
|
|
85 $root = $nodes->item(0);
|
|
86 return self::_parseCommandNode($root, true);
|
|
87 }
|
|
88
|
|
89 // }}}
|
|
90 // validate() {{{
|
|
91
|
|
92 /**
|
|
93 * Validates the xml definition using Relax NG.
|
|
94 *
|
|
95 * @param DomDocument $doc The document to validate
|
|
96 *
|
|
97 * @return boolean Whether the xml data is valid or not.
|
|
98 * @throws Console_CommandLine_Exception
|
|
99 * @todo use exceptions
|
|
100 */
|
|
101 public static function validate($doc)
|
|
102 {
|
|
103 $pkgRoot = __DIR__ . '/../../';
|
|
104 $paths = array(
|
|
105 // PEAR/Composer
|
|
106 '@data_dir@/Console_CommandLine/data/xmlschema.rng',
|
|
107 // Composer
|
|
108 $pkgRoot . 'data/Console_CommandLine/data/xmlschema.rng',
|
|
109 $pkgRoot . 'data/console_commandline/data/xmlschema.rng',
|
|
110 // Git
|
|
111 $pkgRoot . 'data/xmlschema.rng',
|
|
112 'xmlschema.rng',
|
|
113 );
|
|
114
|
|
115 foreach ($paths as $path) {
|
|
116 if (is_readable($path)) {
|
|
117 return $doc->relaxNGValidate($path);
|
|
118 }
|
|
119 }
|
|
120 Console_CommandLine::triggerError(
|
|
121 'invalid_xml_file',
|
|
122 E_USER_ERROR, array('{$file}' => $rngfile));
|
|
123 }
|
|
124
|
|
125 // }}}
|
|
126 // _parseCommandNode() {{{
|
|
127
|
|
128 /**
|
|
129 * Parses the root command node or a command node and returns the
|
|
130 * constructed Console_CommandLine or Console_CommandLine_Command instance.
|
|
131 *
|
|
132 * @param DomDocumentNode $node The node to parse
|
|
133 * @param bool $isRootNode Whether it is a root node or not
|
|
134 *
|
|
135 * @return mixed Console_CommandLine or Console_CommandLine_Command
|
|
136 */
|
|
137 private static function _parseCommandNode($node, $isRootNode = false)
|
|
138 {
|
|
139 if ($isRootNode) {
|
|
140 $obj = new Console_CommandLine();
|
|
141 } else {
|
|
142 include_once 'Console/CommandLine/Command.php';
|
|
143 $obj = new Console_CommandLine_Command();
|
|
144 }
|
|
145 foreach ($node->childNodes as $cNode) {
|
|
146 $cNodeName = $cNode->nodeName;
|
|
147 switch ($cNodeName) {
|
|
148 case 'name':
|
|
149 case 'description':
|
|
150 case 'version':
|
|
151 $obj->$cNodeName = trim($cNode->nodeValue);
|
|
152 break;
|
|
153 case 'add_help_option':
|
|
154 case 'add_version_option':
|
|
155 case 'force_posix':
|
|
156 $obj->$cNodeName = self::_bool(trim($cNode->nodeValue));
|
|
157 break;
|
|
158 case 'option':
|
|
159 $obj->addOption(self::_parseOptionNode($cNode));
|
|
160 break;
|
|
161 case 'argument':
|
|
162 $obj->addArgument(self::_parseArgumentNode($cNode));
|
|
163 break;
|
|
164 case 'command':
|
|
165 $obj->addCommand(self::_parseCommandNode($cNode));
|
|
166 break;
|
|
167 case 'aliases':
|
|
168 if (!$isRootNode) {
|
|
169 foreach ($cNode->childNodes as $subChildNode) {
|
|
170 if ($subChildNode->nodeName == 'alias') {
|
|
171 $obj->aliases[] = trim($subChildNode->nodeValue);
|
|
172 }
|
|
173 }
|
|
174 }
|
|
175 break;
|
|
176 case 'messages':
|
|
177 $obj->messages = self::_messages($cNode);
|
|
178 break;
|
|
179 default:
|
|
180 break;
|
|
181 }
|
|
182 }
|
|
183 return $obj;
|
|
184 }
|
|
185
|
|
186 // }}}
|
|
187 // _parseOptionNode() {{{
|
|
188
|
|
189 /**
|
|
190 * Parses an option node and returns the constructed
|
|
191 * Console_CommandLine_Option instance.
|
|
192 *
|
|
193 * @param DomDocumentNode $node The node to parse
|
|
194 *
|
|
195 * @return Console_CommandLine_Option The built option
|
|
196 */
|
|
197 private static function _parseOptionNode($node)
|
|
198 {
|
|
199 include_once 'Console/CommandLine/Option.php';
|
|
200 $obj = new Console_CommandLine_Option($node->getAttribute('name'));
|
|
201 foreach ($node->childNodes as $cNode) {
|
|
202 $cNodeName = $cNode->nodeName;
|
|
203 switch ($cNodeName) {
|
|
204 case 'choices':
|
|
205 foreach ($cNode->childNodes as $subChildNode) {
|
|
206 if ($subChildNode->nodeName == 'choice') {
|
|
207 $obj->choices[] = trim($subChildNode->nodeValue);
|
|
208 }
|
|
209 }
|
|
210 break;
|
|
211 case 'messages':
|
|
212 $obj->messages = self::_messages($cNode);
|
|
213 break;
|
|
214 default:
|
|
215 if (property_exists($obj, $cNodeName)) {
|
|
216 $obj->$cNodeName = trim($cNode->nodeValue);
|
|
217 }
|
|
218 break;
|
|
219 }
|
|
220 }
|
|
221 if ($obj->action == 'Password') {
|
|
222 $obj->argument_optional = true;
|
|
223 }
|
|
224 return $obj;
|
|
225 }
|
|
226
|
|
227 // }}}
|
|
228 // _parseArgumentNode() {{{
|
|
229
|
|
230 /**
|
|
231 * Parses an argument node and returns the constructed
|
|
232 * Console_CommandLine_Argument instance.
|
|
233 *
|
|
234 * @param DomDocumentNode $node The node to parse
|
|
235 *
|
|
236 * @return Console_CommandLine_Argument The built argument
|
|
237 */
|
|
238 private static function _parseArgumentNode($node)
|
|
239 {
|
|
240 include_once 'Console/CommandLine/Argument.php';
|
|
241 $obj = new Console_CommandLine_Argument($node->getAttribute('name'));
|
|
242 foreach ($node->childNodes as $cNode) {
|
|
243 $cNodeName = $cNode->nodeName;
|
|
244 switch ($cNodeName) {
|
|
245 case 'description':
|
|
246 case 'help_name':
|
|
247 case 'default':
|
|
248 $obj->$cNodeName = trim($cNode->nodeValue);
|
|
249 break;
|
|
250 case 'multiple':
|
|
251 $obj->multiple = self::_bool(trim($cNode->nodeValue));
|
|
252 break;
|
|
253 case 'optional':
|
|
254 $obj->optional = self::_bool(trim($cNode->nodeValue));
|
|
255 break;
|
|
256 case 'choices':
|
|
257 foreach ($cNode->childNodes as $subChildNode) {
|
|
258 if ($subChildNode->nodeName == 'choice') {
|
|
259 $obj->choices[] = trim($subChildNode->nodeValue);
|
|
260 }
|
|
261 }
|
|
262 break;
|
|
263 case 'messages':
|
|
264 $obj->messages = self::_messages($cNode);
|
|
265 break;
|
|
266 default:
|
|
267 break;
|
|
268 }
|
|
269 }
|
|
270 return $obj;
|
|
271 }
|
|
272
|
|
273 // }}}
|
|
274 // _bool() {{{
|
|
275
|
|
276 /**
|
|
277 * Returns a boolean according to true/false possible strings.
|
|
278 *
|
|
279 * @param string $str The string to process
|
|
280 *
|
|
281 * @return boolean
|
|
282 */
|
|
283 private static function _bool($str)
|
|
284 {
|
|
285 return in_array(strtolower((string)$str), array('true', '1', 'on', 'yes'));
|
|
286 }
|
|
287
|
|
288 // }}}
|
|
289 // _messages() {{{
|
|
290
|
|
291 /**
|
|
292 * Returns an array of custom messages for the element
|
|
293 *
|
|
294 * @param DOMNode $node The messages node to process
|
|
295 *
|
|
296 * @return array an array of messages
|
|
297 *
|
|
298 * @see Console_CommandLine::$messages
|
|
299 * @see Console_CommandLine_Element::$messages
|
|
300 */
|
|
301 private static function _messages(DOMNode $node)
|
|
302 {
|
|
303 $messages = array();
|
|
304
|
|
305 foreach ($node->childNodes as $cNode) {
|
|
306 if ($cNode->nodeType == XML_ELEMENT_NODE) {
|
|
307 $name = $cNode->getAttribute('name');
|
|
308 $value = trim($cNode->nodeValue);
|
|
309
|
|
310 $messages[$name] = $value;
|
|
311 }
|
|
312 }
|
|
313
|
|
314 return $messages;
|
|
315 }
|
|
316
|
|
317 // }}}
|
|
318 }
|