Mercurial > pub > Impl
comparison lib/IMPL/XML/SaxParser.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
author | cin |
---|---|
date | Fri, 04 Sep 2015 19:40:23 +0300 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
406:f23fcb19d3c1 | 407:c6e90e02dd17 |
---|---|
1 package IMPL::XML::SaxParser; | |
2 use strict; | |
3 | |
4 use IMPL::Const qw(:prop); | |
5 use IMPL::declare { | |
6 require => { | |
7 XMLReader => 'XML::LibXML::Reader', | |
8 Exception => 'IMPL::Exception', | |
9 ArgException => '-IMPL::InvalidArgumentException' | |
10 }, | |
11 base => [ 'IMPL::Object' => undef ], | |
12 props => [ _reader => PROP_RW ] | |
13 }; | |
14 | |
15 BEGIN { | |
16 XMLReader->import; | |
17 } | |
18 | |
19 sub Parse { | |
20 my ( $this, $options ) = @_; | |
21 | |
22 my $reader = $this->_reader( XMLReader->new($options) ); | |
23 | |
24 if ( $reader->read() > 0) { | |
25 $this->ProcessRootNode($reader); | |
26 } | |
27 } | |
28 | |
29 sub ProcessRootNode { | |
30 my ( $this, $reader ) = @_; | |
31 warn "not implemented"; | |
32 } | |
33 | |
34 sub ReadChildren { | |
35 my ( $this, $handler ) = @_; | |
36 | |
37 my $reader = $this->_reader; | |
38 | |
39 # содержимое можеть быть только у не пустых элементов | |
40 if($reader->nodeType == XML_READER_TYPE_ELEMENT && !$reader->isEmptyElement) { | |
41 # нужно прочитать все, что ниже, для этого запоминаем текущий уровень | |
42 my $currentLevel = $reader->depth; | |
43 | |
44 # при чтении и проверке данного условия "съедается" закрывающий теэг текущего узла | |
45 while($reader->read && $reader->depth > $currentLevel) { | |
46 # при обходе дочерних узлов нужно пропустить закрывающие узлы | |
47 $this->$handler($reader) | |
48 if $handler and $reader->nodeType != XML_READER_TYPE_END_ELEMENT; | |
49 } | |
50 } | |
51 } | |
52 | |
53 sub ReadTextNode { | |
54 my ($this) = @_; | |
55 | |
56 my $text = ""; | |
57 | |
58 my $handler; | |
59 $handler = sub { | |
60 my ( $me, $reader ) = @_; | |
61 if ( $reader->nodeType == XML_READER_TYPE_TEXT ) { | |
62 $text .= $reader->value; | |
63 } else { | |
64 $this->ReadChildren($handler); | |
65 } | |
66 }; | |
67 | |
68 $this->ReadChildren($handler); | |
69 | |
70 return $text; | |
71 } | |
72 | |
73 sub ReadComplexContent { | |
74 goto &ReadComplexNode; | |
75 } | |
76 | |
77 sub ReadComplexNode { | |
78 my ( $this, $schema ) = @_; | |
79 | |
80 if ( ref $schema eq 'HASH' ) { | |
81 my %data; | |
82 | |
83 my ($handlers,$aliases); | |
84 while(my ($selector,$handler) = each %$schema) { | |
85 my ($alias,$node) = split /:/, $selector; | |
86 $node ||= $alias; | |
87 $handlers->{$node} = $handler; | |
88 $aliases->{$node} = $alias; | |
89 } | |
90 | |
91 $this->ReadChildren( | |
92 sub { | |
93 my ( $me, $node ) = @_; | |
94 | |
95 my $name = $node->localName; | |
96 my $alias = $aliases->{$name}; | |
97 if ( my $handler = $handlers->{$name} ) { | |
98 if (ref $handler eq 'ARRAY') { | |
99 push @{$data{$alias}}, $me->ReadComplexNode($$handler[0]); | |
100 } else { | |
101 $data{$alias} = $me->ReadComplexNode($handler); | |
102 } | |
103 } else { | |
104 $me->ReadChildren(); | |
105 } | |
106 } | |
107 ); | |
108 | |
109 return \%data; | |
110 } | |
111 elsif ( ref $schema eq 'CODE' or not ref $schema ) { | |
112 return $this->$schema($this->_reader); | |
113 } | |
114 else { | |
115 die ArgException->new( schema => 'An invalid schema is supplied' ); | |
116 } | |
117 } | |
118 | |
119 sub attribute { | |
120 shift->_reader->getAttribute(shift); | |
121 } | |
122 | |
123 1; | |
124 | |
125 __END__ | |
126 | |
127 =pod | |
128 | |
129 =head1 NAME | |
130 | |
131 =head1 DESCRIPTION | |
132 | |
133 =head1 MEMBERS | |
134 | |
135 =head2 ReadComplexNode($schema) | |
136 | |
137 =begin code | |
138 | |
139 { | |
140 comments => sub { shift->ReadTextNode }, | |
141 data => [ { | |
142 location => sub { $_[1]->getAttribute('href')} , | |
143 timestamp => 'ReadTextNode' | |
144 } ] | |
145 } | |
146 | |
147 =end code | |
148 | |
149 =cut |