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);
16 $class = ref($class) || $class;
17 return bless(\%args,$class);
33 $self->{xmlfile} = $xml;
35 return $self->{xmlfile};
40 my $doc = $self->{doc};
42 $xml ||= $self->{xml};
43 $doc = $self->{doc} = $parser->parse_string( $xml );
51 $self->xml_to_doc( $xml );
52 my $nodeset = $self->_xml_to_nodeset;
58 return $self->{nodelist};
61 sub xmlfile_to_nodeset {
62 my($self, $xmlfile) = @_;
63 $self->xmlfile( $xmlfile );
64 $self->xmlfile_to_doc;
65 return $self->xml_to_nodeset;
74 my($self, $xmlfile) = @_;
75 $xmlfile ||= $self->xmlfile;
76 my $doc = $self->{doc};
78 $doc = $self->{doc} = $parser->parse_file( $xmlfile );
85 $nodeset ||= $self->nodeset;
87 my $doc = XML::LibXML::Document->new;
92 for my $node ( @$nodeset ) {
95 $node = Fieldmapper::biblio::record_node->new($node);
97 if ( $node->node_type == XML_ELEMENT_NODE ) {
99 $xml = $doc->createElement( $node->name );
101 $xml->setNodeName($seen_ns{$node->namespace_uri} . ':' .
102 $xml->nodeName) if ($node->namespace_uri and $seen_ns{$node->namespace_uri});
104 } elsif ( $node->node_type == XML_TEXT_NODE ) {
105 $xml = $doc->createTextNode( $node->value );
107 } elsif ( $node->node_type == XML_COMMENT_NODE ) {
108 $xml = $doc->createComment( $node->value );
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);
114 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 0);
116 $seen_ns{$node->value} = $node->name;
119 } elsif ( $node->node_type == XML_ATTRIBUTE_NODE ) {
121 if ($node->namespace_uri) {
122 $_xmllist[$node->parent_node]->setAttributeNS($node->namespace_uri, $node->name, $node->value);
124 $_xmllist[$node->parent_node]->setAttribute($node->name, $node->value);
132 $_xmllist[$node->intra_doc_id] = $xml;
134 if (defined $node->parent_node) {
135 $_xmllist[$node->parent_node]->addChild($xml);
139 $doc->setDocumentElement($_xmllist[0]);
144 sub _xml_to_nodeset {
146 my($self, $doc) = @_;
149 return undef unless($doc);
151 my $node = $doc->documentElement;
152 return undef unless($node);
154 $self->{next_id} = 0;
156 push @{$self->{nodelist}}, _make_node_entry( 0, undef,
157 $node->localname, undef, $node->nodeType, $node->namespaceURI );
159 $self->_nodeset_recurse( $node, 0);
165 sub _make_node_entry {
166 my( $intra_doc, $parent, $name, $value, $type, $namespace ) = @_;
168 my $array = Fieldmapper::biblio::record_node->new();
169 $array->intra_doc_id($intra_doc);
170 $array->parent_node($parent);
172 $array->value($value);
173 $array->node_type($type);
174 $array->namespace_uri($namespace);
179 sub _nodeset_recurse {
181 my( $self, $node, $parent) = @_;
182 return undef unless($node && $node->nodeType == 1);
185 for my $kid ( ($node->getNamespaces, $node->attributes, $node->childNodes) ) {
187 my $type = $kid->nodeType;
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 ));
193 return if ($type == 3);
194 $self->_nodeset_recurse( $kid, $self->{next_id});
200 my $type = 1 << shift();
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);