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 );
98 my $doc = XML::LibXML::Document->new;
103 for my $node ( @{$self->nodeset} ) {
106 $node = Fieldmapper::biblio::record_node->new($node);
108 if ( $node->node_type == XML_ELEMENT_NODE ) {
110 $xml = $doc->createElement( $node->name );
112 $xml->setNodeName($seen_ns{$node->namespace_uri} . ':' .
113 $xml->nodeName) if ($node->namespace_uri and $seen_ns{$node->namespace_uri});
115 } elsif ( $node->node_type == XML_TEXT_NODE ) {
116 $xml = $doc->createTextNode( $node->value );
118 } elsif ( $node->node_type == XML_COMMENT_NODE ) {
119 $xml = $doc->createComment( $node->value );
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);
125 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 0);
127 $seen_ns{$node->value} = $node->name;
130 } elsif ( $node->node_type == XML_ATTRIBUTE_NODE ) {
132 if ($node->namespace_uri) {
133 $_xmllist[$node->parent_node]->setAttributeNS($node->namespace_uri, $node->name, $node->value);
135 $_xmllist[$node->parent_node]->setAttribute($node->name, $node->value);
143 $_xmllist[$node->intra_doc_id] = $xml;
145 if (defined $node->parent_node) {
146 $_xmllist[$node->parent_node]->addChild($xml);
150 $doc->setDocumentElement($_xmllist[0]);
155 sub _xml_to_nodeset {
157 my($self, $doc) = @_;
160 return undef unless($doc);
162 my $node = $doc->documentElement;
163 return undef unless($node);
165 $self->{next_id} = 0;
167 push @{$self->nodeset}, _make_node_entry( 0, undef,
168 $node->localname, undef, $node->nodeType, $node->namespaceURI );
170 $self->_nodeset_recurse( $node, 0);
176 sub _make_node_entry {
177 my( $intra_doc, $parent, $name, $value, $type, $namespace ) = @_;
179 my $array = Fieldmapper::biblio::record_node->new();
180 $array->intra_doc_id($intra_doc);
181 $array->parent_node($parent);
183 $array->value($value);
184 $array->node_type($type);
185 $array->namespace_uri($namespace);
190 sub _nodeset_recurse {
192 my( $self, $node, $parent) = @_;
193 return undef unless($node && $node->nodeType == 1);
196 for my $kid ( ($node->getNamespaces, $node->attributes, $node->childNodes) ) {
198 my $type = $kid->nodeType;
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 ));
204 return if ($type == 3);
205 $self->_nodeset_recurse( $kid, $self->{next_id});
211 my $type = 1 << shift();
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);