]> git.sesse.net Git - xml-template/commitdiff
Initial checkin.
authorsgunderson@bigfoot.com <>
Fri, 11 Aug 2006 21:17:47 +0000 (23:17 +0200)
committersgunderson@bigfoot.com <>
Fri, 11 Aug 2006 21:17:47 +0000 (23:17 +0200)
XML/Template.pm [new file with mode: 0644]
attribute.pl [new file with mode: 0644]
attribute2.pl [new file with mode: 0644]
clone.pl [new file with mode: 0644]
clone.xml [new file with mode: 0644]
include.pl [new file with mode: 0644]
included.xml [new file with mode: 0644]
master.xml [new file with mode: 0644]
simple.pl [new file with mode: 0644]
simple.xml [new file with mode: 0644]

diff --git a/XML/Template.pm b/XML/Template.pm
new file mode 100644 (file)
index 0000000..3762fe6
--- /dev/null
@@ -0,0 +1,165 @@
+#! /usr/bin/perl
+use XML::DOM;
+use XML::Parser;
+use XML::NamespaceSupport;
+use Scalar::Util;
+package XML::Template;
+
+sub process_file {
+       my ($filename, $obj, $clean) = @_;
+
+       my $parser = XML::DOM::Parser->new;
+       my $doc = $parser->parsefile($filename);
+
+       process($doc, $obj, $clean);
+
+       return $doc;
+}
+
+sub process {
+       my ($node, $obj, $clean, $nsup) = @_;
+       $clean = 1 unless (defined($clean));
+
+       if (!defined($nsup)) {
+               $nsup = XML::NamespaceSupport->new;
+       }
+       $nsup->push_context;
+
+       # see if this node contains any namespace declarations that are relevant
+       # for us
+       my $attrs = $node->getAttributes;
+       if (defined($attrs)) {
+               for my $attr ($attrs->getValues) {
+                       my $name = $attr->getName;
+                       if ($name =~ /^xmlns:(.*)$/) {
+                               $nsup->declare_prefix($1, $attr->getValue);
+                               $node->removeAttribute($name) if ($clean);
+                       }
+               }
+       }
+       
+       if (!ref($obj)) {                                                       # overwrite
+               for my $child ($node->getChildNodes) {
+                       $node->removeChild($child);
+               }
+               $node->addText($obj);
+       } elsif (Scalar::Util::blessed($obj) && $obj->isa('XML::DOM::Node')) {  # overwrite
+               for my $child ($node->getChildNodes) {
+                       $node->removeChild($child);
+               }
+
+               if ($obj->isa('XML::DOM::Document')) {
+                       $obj = $obj->getDocumentElement;
+               }
+
+               my $newobj = $obj->cloneNode(1);
+               if ($node->isa('XML::DOM::Document')) {
+                       $newobj->setOwnerDocument($node);
+               } else {
+                       $newobj->setOwnerDocument($node->getOwnerDocument);
+               }
+               $node->appendChild($newobj);
+       } elsif (ref($obj) eq 'HASH') {                                         # substitute
+               for my $child ($node->getChildNodes) {
+                       my $processed = 0;
+
+                       if ($child->getNodeType == XML::DOM::ELEMENT_NODE) {
+                               my (undef, undef, $tag) = $nsup->process_element_name($child->getTagName);
+
+                               my $id;
+                               my $attrs = $child->getAttributes;
+                               if (defined($attrs)) {
+                                       for my $attr ($attrs->getValues) {
+                                               next if ($attr->getName =~ /^xmlns(:|$)/);
+
+                                               my ($nsuri, $prefix, $tag) = $nsup->process_attribute_name($attr->getName);
+                                               $id = $attr->getValue;
+                                               $child->removeAttribute($attr->getName) if ($clean);
+                                       }
+                               }
+
+                               # check all substitutions to see if we found anything
+                               # appropriate
+                               for my $key (keys %$obj) {
+                                       if (($key =~ /^\Q$tag\E\.(.*)$/) ||
+                                           (defined($id) && $key =~ /^#\Q$id\E\.(.*)$/)) {
+                                               $child->setAttribute($1, $obj->{$key});
+                                       }
+
+                                       next if ($processed);
+                                       if ($key eq $tag || (defined($id) && $key =~ /^#\Q$id\E$/)) {
+                                               process($child, $obj->{$key}, $clean, $nsup);
+                                               $processed = 1;
+                                       }
+                               }
+                       }
+
+                       process($child, $obj, $clean, $nsup) unless ($processed);
+               }
+       } elsif (ref($obj) eq 'ARRAY') {                                        # repeat
+               my $doc = $node->getOwnerDocument;
+               my $frag = $doc->createDocumentFragment;
+
+               for my $child ($node->getChildNodes) {
+                       $frag->appendChild($child);
+               }
+               for my $child ($node->getChildNodes) {
+                       $node->removeChild($child);
+               }
+               
+               for my $instance (@$obj) {
+
+                       my $newnode = $frag->cloneNode(1);
+                       process($newnode, $instance, $clean, $nsup);
+                       $node->appendChild($newnode);
+                       clean($newnode, $nsup) if ($clean);
+               }
+
+               $frag->dispose;
+               $nsup->pop_context;
+               return;
+       }
+
+       clean($node, $nsup) if $clean;
+       $nsup->pop_context;
+}
+
+sub clean {
+       my ($node, $nsup) = @_;
+
+       if ($node->getNodeType == XML::DOM::ELEMENT_NODE) {
+               my ($nsuri) = $nsup->process_element_name($node->getTagName);
+               return unless ($nsuri eq 'http://template.sesse.net/');
+
+               # as this is a dummy node, we want to remove it and move everything further up
+               # after we've done any required replacements
+               my $doc = $node->getOwnerDocument;
+               my $frag = $doc->createDocumentFragment;
+
+               for my $child ($node->getChildNodes) {
+                       $frag->appendChild($child);
+               }
+               for my $child ($node->getChildNodes) {
+                       $node->removeChild($child);
+               }
+
+               my $parent = $node->getParentNode;
+
+               $parent->replaceChild($frag, $node);
+       }
+}
+
+sub alternate {
+       my ($tag, $array, @elems) = @_;
+
+       my $i = 0;
+       my $num = scalar @elems;
+
+       for my $ref (@$array) {
+               $ref->{$tag} = $elems[$i++ % $num];
+       }
+
+       return $array;
+}
+
+1;
diff --git a/attribute.pl b/attribute.pl
new file mode 100644 (file)
index 0000000..16826ca
--- /dev/null
@@ -0,0 +1,13 @@
+#! /usr/bin/perl
+use XML::Template;
+
+my $doc = XML::Template::process_file('clone.xml', {
+       'color' => 'red',
+       '#things' => [
+               { 'li' => 'Raindrops on roses',    'li.class' => 'odd' },
+               { 'li' => 'Whiskers on kittens',   'li.class' => 'even' },
+               { 'li' => 'Bright copper kettles', 'li.class' => 'odd' },
+               { 'li' => 'Warm, woolen mittens',  'li.class' => 'even' }
+       ]
+});
+print $doc->toString;
diff --git a/attribute2.pl b/attribute2.pl
new file mode 100644 (file)
index 0000000..038ae92
--- /dev/null
@@ -0,0 +1,13 @@
+#! /usr/bin/perl
+use XML::Template;
+
+my $doc = XML::Template::process_file('clone.xml', {
+       'color' => 'blue',
+       '#things' => XML::Template::alternate('li.class', [
+               { 'li' => 'Raindrops on roses' },
+               { 'li' => 'Whiskers on kittens' },
+               { 'li' => 'Bright copper kettles' },
+               { 'li' => 'Warm, woolen mittens'},
+       ], 'odd', 'even')
+});
+print $doc->toString;
diff --git a/clone.pl b/clone.pl
new file mode 100644 (file)
index 0000000..0881cb2
--- /dev/null
+++ b/clone.pl
@@ -0,0 +1,13 @@
+#! /usr/bin/perl
+use XML::Template;
+
+my $doc = XML::Template::process_file('clone.xml', {
+       'color' => 'blue',
+       '#things' => [
+               { 'li' => 'Raindrops on roses' },
+               { 'li' => 'Whiskers on kittens' },
+               { 'li' => 'Bright copper kettles' },
+               { 'li' => 'Warm, woolen mittens'} 
+       ]
+});
+print $doc->toString;
diff --git a/clone.xml b/clone.xml
new file mode 100644 (file)
index 0000000..d1cb330
--- /dev/null
+++ b/clone.xml
@@ -0,0 +1,15 @@
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:tmpl="http://template.sesse.net/" xml:lang="en">
+  <head>
+    <title>Cloning test</title>
+  </head>
+  <body>
+     <p>My favourite color is <tmpl:color />; I like that very much.
+       All my favourite things:</p>
+    <ul tmpl:id="things">
+      <li />
+    </ul>
+  </body>
+</html>
diff --git a/include.pl b/include.pl
new file mode 100644 (file)
index 0000000..26b2562
--- /dev/null
@@ -0,0 +1,12 @@
+#! /usr/bin/perl
+use XML::Template;
+
+my $doc = XML::Template::process_file('included.xml', {
+       'color' => 'red'
+});
+my $master = XML::Template::process_file('master.xml', {
+       'title' => 'Main HTML title',
+       'h1' => 'Nice heading here',
+       'contents' => $doc
+});
+print $master->toString;
diff --git a/included.xml b/included.xml
new file mode 100644 (file)
index 0000000..e8658cd
--- /dev/null
@@ -0,0 +1,4 @@
+<p>This document is simply being included into another document by
+  means of attaching DOM nodes together. My favourite color is now
+  <t:color />.
+</p>
diff --git a/master.xml b/master.xml
new file mode 100644 (file)
index 0000000..e3af136
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://template.sesse.net/" xml:lang="en">
+  <head>
+    <title />
+  </head>
+  <body>
+     <h1 />
+     <t:contents />
+     <hr />
+     <p>Copyright information goes here.</p>
+  </body>
+</html>
diff --git a/simple.pl b/simple.pl
new file mode 100644 (file)
index 0000000..04c4eb4
--- /dev/null
+++ b/simple.pl
@@ -0,0 +1,8 @@
+#! /usr/bin/perl
+use XML::Template;
+
+my $doc = XML::Template::process_file('simple.xml', {
+       'title' => 'A very basic example',
+       '#hello' => 'Hello world!'
+});
+print $doc->toString;
diff --git a/simple.xml b/simple.xml
new file mode 100644 (file)
index 0000000..b4bac24
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="http://template.sesse.net/" xml:lang="en">
+  <head>
+    <title />
+  </head>
+  <body>
+    <p t:id="hello">This will be replaced.</p>
+  </body>
+</html>