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;
56 sub xmldoc_to_nodeset {
58 $self->{doc} = $doc if $doc;
59 my $nodeset = $self->_xml_to_nodeset;
65 return $self->{nodelist};
68 sub xmlfile_to_nodeset {
69 my($self, $xmlfile) = @_;
70 $self->xmlfile( $xmlfile );
71 $self->xmlfile_to_doc;
72 return $self->xml_to_nodeset;
81 my($self, $xmlfile) = @_;
82 $xmlfile ||= $self->xmlfile;
83 my $doc = $self->{doc};
85 $doc = $self->{doc} = $parser->parse_file( $xmlfile );
92 $nodeset ||= $self->nodeset;
93 $self->{nodelist} = $nodeset;
95 my $doc = XML::LibXML::Document->new;
100 for my $node ( @$nodeset ) {
103 $node = Fieldmapper::biblio::record_node->new($node);
105 if ( $node->node_type == XML_ELEMENT_NODE ) {
107 $xml = $doc->createElement( $node->name );
109 $xml->setNodeName($seen_ns{$node->namespace_uri} . ':' .
110 $xml->nodeName) if ($node->namespace_uri and $seen_ns{$node->namespace_uri});
112 } elsif ( $node->node_type == XML_TEXT_NODE ) {
113 $xml = $doc->createTextNode( $node->value );
115 } elsif ( $node->node_type == XML_COMMENT_NODE ) {
116 $xml = $doc->createComment( $node->value );
118 } elsif ( $node->node_type == XML_NAMESPACE_DECL ) {
119 if ($self->nodeset->[$node->parent_node]->namespace_uri eq $node->value) {
120 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 1);
122 $_xmllist[$node->parent_node]->setNamespace($node->value, $node->name, 0);
124 $seen_ns{$node->value} = $node->name;
127 } elsif ( $node->node_type == XML_ATTRIBUTE_NODE ) {
129 if ($node->namespace_uri) {
130 $_xmllist[$node->parent_node]->setAttributeNS($node->namespace_uri, $node->name, $node->value);
132 $_xmllist[$node->parent_node]->setAttribute($node->name, $node->value);
140 $_xmllist[$node->intra_doc_id] = $xml;
142 if (defined $node->parent_node) {
143 $_xmllist[$node->parent_node]->addChild($xml);
147 $doc->setDocumentElement($_xmllist[0]);
152 sub _xml_to_nodeset {
154 my($self, $doc) = @_;
157 return undef unless($doc);
159 my $node = $doc->documentElement;
160 return undef unless($node);
162 $self->{next_id} = 0;
164 push @{$self->{nodelist}}, _make_node_entry( 0, undef,
165 $node->localname, undef, $node->nodeType, $node->namespaceURI );
167 $self->_nodeset_recurse( $node, 0);
173 sub _make_node_entry {
174 my( $intra_doc, $parent, $name, $value, $type, $namespace ) = @_;
176 my $array = Fieldmapper::biblio::record_node->new();
177 $array->intra_doc_id($intra_doc);
178 $array->parent_node($parent);
180 $array->value($value);
181 $array->node_type($type);
182 $array->namespace_uri($namespace);
187 sub _nodeset_recurse {
189 my( $self, $node, $parent) = @_;
190 return undef unless($node && $node->nodeType == 1);
193 for my $kid ( ($node->getNamespaces, $node->attributes, $node->childNodes) ) {
195 my $type = $kid->nodeType;
197 push @{$self->{nodelist}}, _make_node_entry( ++$self->{next_id}, $parent,
198 $kid->localname, _grab_content( $kid, $type ),
199 $type, ($type != 18 ? $kid->namespaceURI : undef ));
201 return if ($type == 3);
202 $self->_nodeset_recurse( $kid, $self->{next_id});
208 my $type = 1 << shift();
210 return undef if ($type & 1 << XML_ELEMENT_NODE);
211 return $node->textContent if ($type & $_tC_mask);
212 return $node->value if ($type & $_val_mask);
213 return $node->getData if ($type & 1 << XML_PI_NODE);