summaryrefslogtreecommitdiff
path: root/lib/Text/Restructured/Writer/LibXML.pm
blob: 99ef2062bc5e438c8c36d4660b2e34dd4aea163b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package Text::Restructured::Writer::LibXML; 
use strict;
use warnings;
use XML::LibXML;
 
$Text::Restructured::Writer::LibXML::VERSION='0.01';
 
=head1 NAME
 
Text::Restructured::Writer::LibXML
 
=head1 SYNOPSIS
 
  use Text::Restructured;
  use Text::Restructured::Writer::LibXML;
 
  my $parser=Text::Restructured->new($opts,'gino');
  my $dudom=$parser->Parse($input,$filename);
  my $xdoc=Text::Restructured::Writer::LibXML->new->ProcessDOM($dudom);
 
=head1 DESCRIPTION
 
This module implements a "Writer" for L<Text::Restructured>, that
instead of returning a string, returns a L<XML::LibXML> DOM.
 
The DOM will have non-namespaced elements according to the docutils
vocabulary, and namespcaed elements according to the MathML
vocabulary.
 
This is probably the fastest way to transform a
L<Text::Restructured::DOM> structure into a proper XML DOM.
 
=head1 METHODS
 
=head2 C<new>
 
Returns a new object.
 
=cut
 
sub new {
    my ($class)=@_;
    return bless {},$class;
}
 
=head2 I<xml_dom>C<= ProcessDOM(>I<docutils_dom>C<)>
 
Given an object of type L<Text::Restructured::DOM>, processes it
recursively and builds an XML DOM into a new document. Returns the
document, or dies trying.
 
=cut
 
sub ProcessDOM {
    my ($self,$dudom)=@_;
    my $xdoc=XML::LibXML->createDocument();
    $xdoc->setDocumentElement(_docutils2xml($dudom,$xdoc));
    return $xdoc;
}
 
my $MATHML='http://www.w3.org/1998/Math/MathML';
 
sub _mathml2xml {
    my ($mnode,$xdoc)=@_;
 
    if ($mnode->isText) {
        return $xdoc->createTextNode($mnode->nodeValue);
    }
 
 
    my @children=map {_mathml2xml($_,$xdoc)}
        $mnode->childNodes();
 
    my $elem=$xdoc->createElementNS($MATHML,$mnode->nodeName);
    for my $attname ($mnode->attributeList) {
        next if $attname eq 'xmlns';
        $elem->setAttribute($attname,
                            $mnode->attribute($attname))
    }
 
    $elem->appendChild($_for @children;
 
    return $elem;
}
 
sub _docutils2xml {
    my ($dunode,$xdoc)=@_;
 
    if ($dunode->{tageq '#PCDATA') {
        return $xdoc->createTextNode($dunode->{text} || '');
    }
 
    if ($dunode->{tageq 'mathml') {
        return _mathml2xml($dunode->{attr}{mathml},$xdoc);
    }
 
    my @children=map {_docutils2xml($_,$xdoc)}
        @{ $dunode->{content} || [] };
 
    my $elem=$xdoc->createElement($dunode->{tag});
 
    if (defined $dunode->{attr}) {
        while (my ($attname,$attval)=each %{$dunode->{attr}}) {
            if (! defined $attval) {
                $attval='';
            }
            elsif (ref($attvaleq 'ARRAY') {
                $attval=join ' ',@$attval;
            }
            $elem->setAttribute($attname,$attval);
        }
    }
    $elem->appendChild($_for @children;
 
    return $elem;
}
 
1;