1 use strict; use warnings;
2 package OpenILS::Utils::FlatXML;
4 use OpenILS::Utils::Fieldmapper;
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;
11 my $parser = XML::LibXML->new();
12 $parser->keep_blanks(0);
15 my %args = ( nodeset => [],
21 $class = ref($class) || $class;
22 return bless(\%args,$class);
38 $self->{xmlfile} = $xml;
40 return $self->{xmlfile};
45 my $doc = $self->{doc};
47 $xml ||= $self->{xml};
48 $doc = $self->{doc} = $parser->parse_string( $xml );
56 $self->xml_to_doc( $xml );
57 my $nodeset = $self->_xml_to_nodeset;
61 sub xmldoc_to_nodeset {
63 $self->{doc} = $doc if $doc;
64 my $nodeset = $self->_xml_to_nodeset;
70 return $self->{nodeset};
73 sub xmlfile_to_nodeset {
74 my($self, $xmlfile) = @_;
75 $self->xmlfile( $xmlfile );
76 $self->xmlfile_to_doc;
77 return $self->xml_to_nodeset;
86 my($self, $xmlfile) = @_;
87 $xmlfile ||= $self->xmlfile;
88 my $doc = $self->{doc};
90 $doc = $self->{doc} = $parser->parse_file( $xmlfile );
97 $self->{nodeset} = $nodeset if $nodeset;
99 my $doc = XML::LibXML::Document->new;
104 for my $node ( @{$self->nodeset} ) {
107 $node = Fieldmapper::biblio::record_node->new($node);
109 if ( $node->node_type == XML_ELEMENT_NODE ) {
111 $xml = $doc->createElement( $node->name );
113 $xml->setNodeName($seen_ns{$node->namespace_uri} . ':' .
114 $xml->nodeName) if ($node->namespace_uri and $seen_ns{$node->namespace_uri});
116 } elsif ( $node->node_type == XML_TEXT_NODE ) {
117 $xml = $doc->createTextNode( $node->value );
119 } elsif ( $node->node_type == XML_COMMENT_NODE ) {
120 $xml = $doc->createComment( $node->value );
122 } elsif ( $node->node_type == XML_NAMESPACE_DECL ) {
123 if ($self->nodeset->[$node->parent_node]->namespace_uri eq $node->value) {
124 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 1);
126 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 0);
128 $seen_ns{$node->value} = $node->name;
131 } elsif ( $node->node_type == XML_ATTRIBUTE_NODE ) {
133 if ($node->namespace_uri) {
134 $_xmllist[$node->parent_node]->setAttributeNS($node->namespace_uri, $node->name, $node->value);
136 $_xmllist[$node->parent_node]->setAttribute($node->name, $node->value);
144 $_xmllist[$node->intra_doc_id] = $xml;
146 if (defined $node->parent_node) {
147 $_xmllist[$node->parent_node]->addChild($xml);
151 $doc->setDocumentElement($_xmllist[0]);
156 sub _xml_to_nodeset {
158 my($self, $doc) = @_;
161 return undef unless($doc);
163 my $node = $doc->documentElement;
164 return undef unless($node);
166 $self->{next_id} = 0;
168 push @{$self->nodeset}, _make_node_entry( 0, undef,
169 $node->localname, undef, $node->nodeType, $node->namespaceURI );
171 $self->_nodeset_recurse( $node, 0);
177 sub _make_node_entry {
178 my( $intra_doc, $parent, $name, $value, $type, $namespace ) = @_;
180 my $array = Fieldmapper::biblio::record_node->new();
181 $array->intra_doc_id($intra_doc);
182 $array->parent_node($parent);
184 $array->value($value);
185 $array->node_type($type);
186 $array->namespace_uri($namespace);
191 sub _nodeset_recurse {
193 my( $self, $node, $parent) = @_;
194 return undef unless($node && $node->nodeType == 1);
197 for my $kid ( ($node->getNamespaces, $node->attributes, $node->childNodes) ) {
199 my $type = $kid->nodeType;
201 push @{$self->nodeset}, _make_node_entry( ++$self->{next_id}, $parent,
202 $kid->localname, _grab_content( $kid, $type ),
203 $type, ($type != 18 ? $kid->namespaceURI : undef ));
205 return if ($type == 3);
206 $self->_nodeset_recurse( $kid, $self->{next_id});
212 my $type = 1 << shift();
214 return undef if ($type & 1 << XML_ELEMENT_NODE);
215 return $node->textContent if ($type & $_tC_mask);
216 return $node->value if ($type & $_val_mask);
217 return $node->getData if ($type & 1 << XML_PI_NODE);