@@ -17,37 +17,57 @@ class XmlProcessor
1717 private array $ nodePath = [];
1818 private string $ currentValue = '' ;
1919
20+ private ?array $ skipNodes = NULL ;
21+
2022 private \XMLReader $ xml ;
2123 private XmlProcessorContext $ context ;
2224
2325 /** @var iterable<NodeProcessorInterface> */
2426 private iterable $ processors ;
2527
28+ /** @var iterable<bool> */
29+ private iterable $ parserProperties ;
30+
2631 /**
2732 * @param iterable<NodeProcessorInterface> $processors
28- * @param iterable<bool> $options
33+ * @param iterable<bool> $parserProperties
2934 */
3035 public function __construct (
3136 iterable $ processors ,
32- iterable $ options = []
37+ iterable $ parserProperties = []
3338 )
3439 {
3540 $ this ->xml = new \XMLReader ();
36- foreach ($ options as $ option => $ value ) {
37- $ this ->xml ->setParserProperty ($ option , $ value );
38- }
3941 $ this ->processors = $ processors ;
40- $ this ->context = new XmlProcessorContext ($ this ->xml , $ this ->processors );
42+ $ this ->parserProperties = $ parserProperties ;
43+ $ this ->context = new XmlProcessorContext (
44+ $ this ->xml ,
45+ $ this ->processors ,
46+ fn () => $ this ->skipNode ()
47+ );
4148 }
4249
43- function getProcessorContext ( ): XmlProcessorContext
50+ function setSkipNodes (? array $ skipNodes = NULL ): void
4451 {
45- return $ this ->context ;
52+ $ this ->skipNodes = $ skipNodes ;
53+ }
54+
55+ function getSkipNodes (): ?array
56+ {
57+ return $ this ->skipNodes ;
58+ }
59+
60+ function getProcessor (string $ processorName ): ?NodeProcessorInterface
61+ {
62+ return $ this ->context ->getProcessor ($ processorName );
4663 }
4764
4865 public function processFile (string $ filename ): void
4966 {
5067 $ this ->xml ->open ($ filename );
68+ foreach ($ this ->parserProperties as $ parserProperty => $ value ) {
69+ $ this ->xml ->setParserProperty ($ parserProperty , $ value );
70+ }
5171 $ this ->getProcessorEvents (self ::EVENT_OPEN_FILE );
5272 while ($ this ->xml ->read ()) {
5373 switch ($ this ->xml ->nodeType ) {
@@ -57,6 +77,10 @@ public function processFile(string $filename): void
5777 case \XMLReader::ELEMENT :
5878 $ selfClosing = $ this ->xml ->isEmptyElement ;
5979 $ this ->eventOpenElement ();
80+ if ($ this ->shouldSkipNode ()) {
81+ $ this ->skipNode ();
82+ break ;
83+ }
6084 if ($ selfClosing ) {
6185 $ this ->eventCloseElement ();
6286 }
@@ -73,6 +97,28 @@ public function processFile(string $filename): void
7397 $ this ->xml ->close ();
7498 }
7599
100+ private function skipNode (): bool
101+ {
102+ $ result = $ this ->xml ->next ();
103+ $ this ->eventCloseElement ();
104+ return $ result ;
105+ }
106+
107+ private function shouldSkipNode (): bool
108+ {
109+ if ($ this ->skipNodes === NULL ) {
110+ return false ;
111+ }
112+ $ nodePath = implode ('/ ' , $ this ->nodePath );
113+ foreach ($ this ->skipNodes as $ skipNode ) {
114+ if (self ::checkNodePath ($ nodePath , $ skipNode )) {
115+ return true ;
116+ }
117+ }
118+
119+ return false ;
120+ }
121+
76122 private function eventOpenElement (): void
77123 {
78124 $ this ->pushNodePath ();
@@ -148,4 +194,15 @@ private function createContext(string $contextClass): NodeProcessorContext
148194 }
149195 return $ context ;
150196 }
197+
198+ static function checkNodePath (string $ nodePath , string $ expected ): bool
199+ {
200+ return
201+ $ expected === '/ ' . $ nodePath ||
202+ $ nodePath === $ expected || (
203+ function_exists ('str_end_with ' )
204+ ? str_end_with ($ nodePath , $ expected ) :
205+ substr_compare ($ nodePath , $ expected , -strlen ($ expected )) === 0
206+ );
207+ }
151208}
0 commit comments