]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Utils/FlatXML.pm
renamed nodelist to nodeset
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Utils / FlatXML.pm
1 use strict; use warnings;
2 package OpenILS::Utils::FlatXML;
3 use XML::LibXML;
4 use OpenILS::Utils::Fieldmapper;
5
6
7 my $_tC_mask = 1 << XML_TEXT_NODE | 1 << XML_COMMENT_NODE | 1 << XML_CDATA_SECTION_NODE | 1 << XML_DTD_NODE;
8 my $_val_mask = 1 << XML_ATTRIBUTE_NODE | 1 << XML_NAMESPACE_DECL;
9
10
11 my $parser = XML::LibXML->new();
12 $parser->keep_blanks(0);
13 sub new {
14         my $class = shift;
15         my %args = (    nodeset => [],
16                         xml     => undef,
17                         xmlfile => undef,
18                         doc     => undef,
19                         @_,
20         );
21         $class = ref($class) || $class;
22         return bless(\%args,$class);
23 }
24
25 sub xml {
26         my $self = shift;
27         my $xml = shift;
28         if ($xml) {
29                 $self->{xml} = $xml;
30         }
31         return $self->{xml};
32 }
33
34 sub xmlfile {
35         my $self = shift;
36         my $xml = shift;
37         if ($xml) {
38                 $self->{xmlfile} = $xml;
39         }
40         return $self->{xmlfile};
41 }
42
43 sub xml_to_doc {
44         my($self, $xml) = @_;
45         my $doc = $self->{doc};
46         unless ($doc) {
47                 $xml ||= $self->{xml};
48                 $doc = $self->{doc} = $parser->parse_string( $xml );
49         }
50         return $doc;
51 }
52
53 sub xml_to_nodeset {
54         my($self, $xml) = @_;
55         $xml ||= $self->xml;
56         $self->xml_to_doc( $xml );
57         my $nodeset = $self->_xml_to_nodeset;
58         return $self;
59 }
60
61 sub xmldoc_to_nodeset {
62         my($self, $doc) = @_;
63         $self->{doc} = $doc if $doc;
64         my $nodeset = $self->_xml_to_nodeset;
65         return $self;
66 }
67
68 sub nodeset {
69         my $self = shift;
70         return $self->{nodeset};
71 }
72
73 sub xmlfile_to_nodeset {
74         my($self, $xmlfile) = @_;
75         $self->xmlfile( $xmlfile );
76         $self->xmlfile_to_doc;
77         return $self->xml_to_nodeset;
78 }
79
80 sub doc {
81         my $self = shift;
82         return $self->{doc};
83 }
84
85 sub xmlfile_to_doc {
86         my($self, $xmlfile) = @_;
87         $xmlfile ||= $self->xmlfile;
88         my $doc = $self->{doc};
89         unless ($doc) {
90                 $doc = $self->{doc} = $parser->parse_file( $xmlfile );
91         }
92         return $doc;
93 }
94 sub nodeset_to_xml {
95         my $self = shift;
96         my $nodeset = shift;
97
98         my $doc = XML::LibXML::Document->new;
99
100         my %seen_ns;
101         
102         my @_xmllist;
103         for my $node ( @{$self->nodeset} ) {
104                 my $xml;
105
106                 $node = Fieldmapper::biblio::record_node->new($node);
107
108                 if ( $node->node_type == XML_ELEMENT_NODE ) {
109
110                         $xml = $doc->createElement( $node->name );
111
112                         $xml->setNodeName($seen_ns{$node->namespace_uri} . ':' . 
113                                         $xml->nodeName) if ($node->namespace_uri and $seen_ns{$node->namespace_uri});
114
115                 } elsif ( $node->node_type == XML_TEXT_NODE ) {
116                         $xml = $doc->createTextNode( $node->value );
117                         
118                 } elsif ( $node->node_type == XML_COMMENT_NODE ) {
119                         $xml = $doc->createComment( $node->value );
120                         
121                 } elsif ( $node->node_type == XML_NAMESPACE_DECL ) {
122                         if ($self->nodeset->[$node->parent_node]->namespace_uri eq $node->value) {
123                                 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 1);
124                         } else {
125                                 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 0);
126                         }
127                         $seen_ns{$node->value} = $node->name;
128                         next;
129
130                 } elsif ( $node->node_type == XML_ATTRIBUTE_NODE ) {
131
132                         if ($node->namespace_uri) {
133                                 $_xmllist[$node->parent_node]->setAttributeNS($node->namespace_uri, $node->name, $node->value);
134                         } else {
135                                 $_xmllist[$node->parent_node]->setAttribute($node->name, $node->value);
136                         }
137
138                         next;
139                 } else {
140                         next;
141                 }
142
143                 $_xmllist[$node->intra_doc_id] = $xml;
144
145                 if (defined $node->parent_node) {
146                         $_xmllist[$node->parent_node]->addChild($xml);
147                 }
148         }
149
150         $doc->setDocumentElement($_xmllist[0]);
151
152         return $doc;
153 }
154
155 sub _xml_to_nodeset {
156
157         my($self, $doc) = @_;
158
159         $doc ||= $self->doc;
160         return undef unless($doc);
161
162         my $node = $doc->documentElement;
163         return undef unless($node);
164
165         $self->{next_id} = 0;
166
167         push @{$self->nodeset}, _make_node_entry( 0, undef, 
168                         $node->localname, undef, $node->nodeType, $node->namespaceURI );
169
170         $self->_nodeset_recurse( $node, 0);
171
172         return  $self;
173 }
174
175
176 sub _make_node_entry {
177         my( $intra_doc, $parent, $name, $value, $type, $namespace ) = @_;
178
179         my $array = Fieldmapper::biblio::record_node->new();
180         $array->intra_doc_id($intra_doc);
181         $array->parent_node($parent);
182         $array->name($name);
183         $array->value($value);
184         $array->node_type($type);
185         $array->namespace_uri($namespace);
186         return $array;
187 }
188
189
190 sub _nodeset_recurse {
191
192         my( $self, $node, $parent) = @_;
193         return undef unless($node && $node->nodeType == 1);
194
195
196         for my $kid ( ($node->getNamespaces, $node->attributes, $node->childNodes) ) {
197
198                 my $type = $kid->nodeType;
199
200                 push @{$self->nodeset}, _make_node_entry( ++$self->{next_id}, $parent,
201                         $kid->localname, _grab_content( $kid, $type ), 
202                         $type, ($type != 18 ? $kid->namespaceURI : undef ));
203
204                 return if ($type == 3);
205                 $self->_nodeset_recurse( $kid, $self->{next_id});
206         }
207 }
208
209 sub _grab_content {
210         my $node = shift;
211         my $type = 1 << shift();
212
213         return undef if ($type & 1 << XML_ELEMENT_NODE);
214         return $node->textContent if ($type & $_tC_mask);
215         return $node->value if ($type & $_val_mask);
216         return $node->getData if ($type & 1 << XML_PI_NODE);
217 }
218
219 1;