File Coverage

blib/lib/XML/SimpleObject/LibXML.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package XML::SimpleObject::LibXML;
2              
3 1     1   30385 use strict;
  1         3  
  1         39  
4 1     1   7671 use XML::LibXML 1.53;
  0            
  0            
5             use XML::LibXML::Common;
6              
7             our $VERSION = '0.60';
8              
9             sub attributes {
10             my $self = shift;
11             my $name = shift;
12             my %attributes;
13             my @attrs = $self->{_DOM}->getAttributes;
14             foreach my $attribute (@attrs) {
15             $attributes{$attribute->getName} = $attribute->value;
16             }
17             return %attributes;
18             }
19              
20             sub attribute {
21             my $self = shift;
22             my $name = shift;
23             my $newvalue = shift;
24             if ($self->hasNamespaces()) {
25             my ($namespaceURI, $localName) = $self->_parseTagName($name, ATTRIBUTE_NODE);
26              
27             if (defined($namespaceURI)) { # Attribute has an explicit namespace
28             my ($found) = $self->{_DOM}->getAttributeNodeNS($namespaceURI, $localName);
29             if ($found) {
30             if ($newvalue) {
31             $found->setValue($newvalue);
32             } else {
33             return $found->value;
34             }
35             }
36             } else { # Attribute has no namespace
37             my ($found) = $self->{_DOM}->getAttributeNode($name);
38             if ($found) {
39             if ($newvalue) {
40             $found->setValue($newvalue);
41             } else {
42             return $found->value;
43             }
44             }
45             }
46              
47             } else {
48             my ($found) = $self->{_DOM}->findnodes("\@$name");
49             if ($found) {
50             if ($newvalue) {
51             $found->setValue($newvalue);
52             } else {
53             return $found->value;
54             }
55             }
56             }
57             }
58              
59             sub add_attribute {
60             my $self = shift;
61             $self->{_DOM}->setAttribute( $_[0], $_[1] );
62             return $self;
63             }
64              
65             sub value {
66             my $node = shift;
67             my $newvalue = shift;
68             my ($found) = $node->{_DOM}->findnodes("text()");
69             if ($found) {
70             if (defined $newvalue) {
71             return $found->setData($newvalue);
72             } else {
73             return $found->getData();
74             }
75             }
76             }
77              
78             sub name {
79             my $node = shift;
80             my $newname = shift;
81             if ($newname) {
82             $node->{_DOM}->setNodeName($newname);
83             } else {
84             $node->{_DOM}->getName;
85             }
86             }
87              
88             sub type {
89             $_[0]->{_DOM}->nodeType;
90             }
91              
92             sub xpath_search {
93             my $self = shift;
94             my $xpath = shift;
95             my @nodes;
96             foreach my $node ($self->{_DOM}->findnodes($xpath)) {
97             my $newobj = new XML::SimpleObject::LibXML ($node);
98             return $newobj unless wantarray;
99             push @nodes, $newobj;
100             }
101             return @nodes;
102             }
103              
104             sub namespaceURI() {
105             $_[0]->{_DOM}->getNamespaceURI();
106             }
107              
108             sub namespace() {
109             my $node = shift;
110             my $namespaceURI = $node->namespaceURI();
111              
112             return unless (defined $namespaceURI);
113              
114             my (@found) = $node->{_DOM}->findnodes("namespace::*"); for (@found) {
115             return $_->getLocalName() if $namespaceURI eq $_->getData();
116             }
117             }
118              
119             sub hasNamespaces() {
120             return $_[0]->{_NAMESPACES};
121             }
122              
123             sub _parseTagName($$) {
124             my ($self, $tag, $type) = @_;
125              
126             my ($namespaceURI, $localName);
127              
128             if ($tag =~ /^([^:]+):(.*)/) {
129             # Tag has an explicit namespace
130             $namespaceURI = $self->{_NAMESPACES}->{$1};
131             $localName = $2;
132             die("Unknown namespace $1") unless ($namespaceURI);
133             }
134             else {
135             $localName = $tag;
136             # Tag has no explicit namespace.
137             if ($type eq ELEMENT_NODE) {
138             # Elements live in the default namespace.
139             # Go with the default namespace. If one was specified, it will be ''.
140             $namespaceURI = $self->{_NAMESPACES}->{''};
141             }
142             elsif ($type eq ATTRIBUTE_NODE) {
143             # The default namespace does not apply to attribute names.
144             # (See http://www.w3.org/TR/1998/PR-xml-names-19981117, section 5.3)
145             }
146             else {
147             # Nothing else has tagnames.
148             die("Unexpected type $type");
149             }
150             }
151              
152             return ($namespaceURI, $localName);
153             }
154              
155             sub child {
156             my $self = shift;
157             my $tag = shift;
158             if (ref $self->{_DOM} eq "XML::LibXML::Document") {
159             my $node = new XML::SimpleObject::LibXML ($self->{_DOM}->documentElement());
160             return $node;
161             }
162             elsif ($self->hasNamespaces()) {
163             my ($namespaceURI, $localName) = $self->_parseTagName($tag, ELEMENT_NODE);
164             my ($element) = $self->{_DOM}->getElementsByTagNameNS($namespaceURI, $localName);
165             return unless ($element);
166             my $node = new XML::SimpleObject::LibXML ($element);
167             return $node;
168             }
169             else
170             {
171             my ($element) = $self->{_DOM}->getElementsByTagName($tag);
172             return unless ($element);
173             my $node = new XML::SimpleObject::LibXML ($element);
174             return $node;
175             }
176             }
177              
178             sub add_child {
179             my $self = shift;
180             my $element = $self->{_DOM}->addNewChild( undef, $_[0]);
181             if ($_[1]) {
182             $element->appendTextNode($_[1]);
183             }
184             my $node = new XML::SimpleObject::LibXML ($element);
185             return $node;
186             }
187              
188             sub delete {
189             my $self = shift;
190             $self->{_DOM}->unbindNode;
191             }
192              
193             sub children_names {
194             my $self = shift;
195             my @elements;
196             foreach my $node ($self->{_DOM}->getChildnodes)
197             {
198             next if ($node->nodeType == 3);
199             push @elements, $node->getName;
200             }
201             return @elements;
202             }
203              
204             sub children {
205             my $self = shift;
206             my $tag = shift;
207             if (ref $self->{_DOM} eq "XML::LibXML::Document") {
208             my $node = new XML::SimpleObject::LibXML ($self->{_DOM}->documentElement());
209             return $node;
210             }
211             elsif (defined($tag)) { # tag: return matching children
212             if ($self->hasNamespaces()) {
213             my ($namespaceURI, $localName) = $self->_parseTagName($tag, ELEMENT_NODE);
214             my @nodelist;
215             foreach my $node ($self->{_DOM}->getElementsByTagNameNS($namespaceURI, $localName)) {
216             next if ($node->nodeType == TEXT_NODE);
217             push @nodelist, new XML::SimpleObject::LibXML ($node);
218             }
219             return @nodelist;
220             }
221             else {
222             my @nodelist;
223             foreach my $node ($self->{_DOM}->getElementsByTagName($tag)) {
224             next if ($node->nodeType == TEXT_NODE);
225             push @nodelist, new XML::SimpleObject::LibXML ($node);
226             }
227             return @nodelist;
228             }
229             }
230             else # no tag: return all children
231             {
232             my @nodelist;
233             foreach my $node ($self->{_DOM}->getChildnodes()) {
234             next if ($node->nodeType == 3);
235             push @nodelist, new XML::SimpleObject::LibXML ($node);
236             }
237             return @nodelist;
238             }
239             }
240              
241             sub output_xml {
242             my $self = shift;
243             my %args = @_;
244             return $self->{_DOM}->toString($args{indent},$args{original_encoding});
245             }
246              
247             sub output_xml_file {
248             my $self = shift;
249             my %args = @_;
250             open FILE, ">" . $args{file} or die $!;
251             print FILE $self->output_xml(%args);
252             close FILE;
253             }
254              
255             sub replace_names_values {
256             my $self = shift;
257             my %args = @_;
258             foreach my $node ($self->{_DOM}->findnodes($args{xpath})) {
259             $args{name} && do { $node->setNodeName($args{name}) };
260             my $nodetype = $node->nodeType;
261             if ($nodetype == 1) { # Element, try text node
262             $args{value} && do {
263             my ($found) = $node->findnodes("text()");
264             $found->setData($args{value});
265             };
266             } elsif ($nodetype == 2) { # Attribute
267             $args{value} && do { $node->setValue($args{value}) };
268             } elsif ($nodetype == 3) { # Text
269             $node->setData($args{value});
270             }
271             }
272             }
273              
274             sub delete_nodes {
275             my $self = shift;
276             my %args = @_;
277             foreach my $node ($self->{_DOM}->findnodes($args{xpath})) {
278             $node->unbindNode();
279             }
280             }
281              
282             sub _build_namespace_map() {
283             my $self = shift;
284             return if $self->{_NAMESPACES};
285              
286             my %map = map { my $key = $_->getLocalName(); $key = '' unless defined $key; $key => $_->getData() } $self->{_DOM}->findnodes("namespace::*");
287             $self->{_NAMESPACES} = \%map if (scalar(%map));
288             }
289              
290             sub _init() {
291             my $self = shift;
292             $self->_build_namespace_map();
293             }
294              
295             sub new {
296             my $class = shift;
297             if (ref($_[0]) =~ /^XML\:\:LibXML/) {
298             my $self = {};
299             bless ($self,$class);
300             $self->{_DOM} = $_[0];
301             $self->_init();
302             return $self;
303             } else {
304             my %args = @_;
305             my $parser = new XML::LibXML;
306             my $dom;
307             if ($args{XML}) {
308             $dom = $parser->parse_string($args{XML});
309             } elsif ($args{file}) {
310             $dom = $parser->parse_file($args{file});
311             } else {
312             die "new() not called with DOM, XML string, or filename";
313             }
314             my $self = {};
315             bless ($self,$class);
316             $self->{_NAME} = "";
317             $self->{_DOM} = $dom;
318             $self->_init();
319             return $self;
320             }
321             }
322              
323              
324             1;
325             __END__