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