Revision: 119
Author: matt
Date: 2006-08-24 00:06:56 +0000 (Thu, 24 Aug 2006)
Log Message:
-----------
Oopsie - forgot to check these into SVN
Added Paths:
-----------
trunk/lib/AxKit2/XSP/
trunk/lib/AxKit2/XSP/SimpleTaglib.pm
trunk/lib/AxKit2/XSP/TaglibHelper.pm
Added: trunk/lib/AxKit2/XSP/SimpleTaglib.pm
===================================================================
--- trunk/lib/AxKit2/XSP/SimpleTaglib.pm 2006-08-24 00:05:52 UTC (rev
118)
+++ trunk/lib/AxKit2/XSP/SimpleTaglib.pm 2006-08-24 00:06:56 UTC (rev
119)
@@ -0,0 +1,1342 @@
+# Copyright 2001-2006 The Apache Software Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Apache::AxKit::XSP::Language::SimpleTaglib - alternate taglib helper code
+package AxKit2::XSP::SimpleTaglib;
+require 5.006;
+use strict;
+use base 'AxKit2::Transformer::XSP';
+use Data::Dumper;
+eval { require WeakRef; };
+eval { require XML::Smart; };
+use attributes;
+our $VERSION = 0.3;
+
+# utility functions
+
+sub makeSingleQuoted($) { $_ = shift; s/([\\%])/\\$1/g; 'q%'.$_.'%'; }
+sub _makeAttributeQuoted(@) { $_ = join(',',@_); s/([\\()])/\\$1/g;
'('.$_.')'; }
+sub makeVariableName($) { $_ = shift; s/[^a-zA-Z0-9]/_/g; $_; }
+
+my $dumper = new Data::Dumper([]);
+$dumper->Quotekeys(0);
+$dumper->Terse(1);
+$dumper->Indent(0);
+
+# perl attribute handlers
+
+my %handlerAttributes;
+
+use constant PLAIN => 0;
+use constant EXPR => 1;
+use constant EXPRORNODE => 2;
+use constant NODE => 3;
+use constant EXPRORNODELIST => 4;
+use constant NODELIST => 5;
+use constant STRUCT => 6;
+
+# Memory leak ahead! The '&' construct may create circular references, which
perl
+# can't clean up. But this has only an effect if a taglib is reloaded, which
shouldn't
+# happen on production machines. Moreover, '&' is rather unusual.
+# If you have the WeakRef module installed, this warning does not apply.
+sub parseChildStructSpec {
+ my ($specs, $refs) = @_;
+ for my $spec ($_[0]) {
+ my $result = {};
+ while (length($spec)) {
+ $spec = substr($spec,1), return $result if (substr($spec,0,1) eq
'}');
+ (my ($type, $token, $next) = ($spec =~ m/^([!\&[EMAIL
PROTECTED])([^ {}]+)(.|$)/))
+ || die("childStruct specification invalid. Parse error at:
'$spec'");
+ substr($spec,0,length($token)+1+($type?1:0)) = '';
+ #warn("type: $type, token: $token, next: $next, spec: $spec");
+ my ($realtoken, $params);
+ if ((($realtoken,$params) = ($token =~ m/^([^\(]+)((?:\([^
\)]+\))+)$/))) {
+ my $i = 0;
+ $token = $realtoken;
+ $$result{$token}{'param'} = { map { $_ => $i++ } ($params =~
m/\(([^ )]+)\)/g) };
+ }
+ if ($type eq '&') {
+ ($$result{$token} = $$refs{$token})
+ || die("childStruct specification invalid. '&' reference
not found.");
+ die("childStruct specification invalid. '&' cannot be used on
'*' nodes.")
+ if ($$result{$token}{'type'} eq '*');
+ die("childStruct specification invalid. '&' may only take a
reference.")
+ if $$result{'param'};
+ eval { WeakRef::weaken($$result{$token}) };
+ return $result if (!$next || $next eq '}');
+ next;
+ }
+ $$result{$token}{'type'} = $type || '$';
+ die("childStruct specification invalid. '${type}' cannot be used
with '{'.")
+ if ($next eq '{' and ($type eq '*' || $type eq '!'));
+ die("childStruct specification invalid. '${type}' cannot be used
with '(,,,)'.")
+ if ($$result{$token}{'param'} and ($type eq '*' || $type eq
'!'));
+ die("childStruct specification invalid. '**' is not supported.")
+ if ($token eq '*' and $type eq '*');
+ $$result{''}{'name'} = $token if ($type eq '*');
+ $$result{$token}{'name'} = $token;
+ return $result if (!$next || $next eq '}');
+ ($$result{$token}{'sub'} = parseChildStructSpec($spec, { %$refs,
$token => $$result{$token} })) || return undef if $next eq '{';
+ }
+ return $result;
+ }
+}
+
+sub serializeChildStructSpec {
+ my ($struct, $refs) = @_;
+ my $result = '';
+ my $first = 1;
+ foreach my $token (keys %$struct) {
+ next unless length($token);
+ $result .= ' ' unless $first;
+ undef $first;
+ if (exists $$refs{$$struct{$token}}) {
+ $result .= '&'.$token;
+ next;
+ }
+ $result .= $$struct{$token}{'type'};
+ $result .= $token;
+ if (exists $$struct{$token}{'param'}) {
+ my %keys = reverse %{$$struct{$token}{'param'}};
+ $result .= '('.join(')(',@keys{0..(scalar(%keys)-1)}).')'
+ }
+ $result .= '{'.serializeChildStructSpec($$struct{$token}{'sub'},{
%$refs, $$struct{$token} => undef }).'}'
+ if exists $$struct{$token}{'sub'};
+ }
+ return $result;
+}
+
+sub MODIFY_CODE_ATTRIBUTES {
+ my ($pkg,$sub,@attr) = @_;
+ return unless defined $sub;
+ my @rest;
+ $handlerAttributes{$sub} ||= {};
+ my $handlerAttributes = $handlerAttributes{$sub};
+ foreach my $a (@attr) {
+ #warn("attr: $a");
+ my ($attr,$param) = ($a =~ m/([^(]*)(?:\((.*)\))?$/);
+ my $warn = 0;
+ $attr =~ s/^XSP_// || $warn++;
+ $param = (defined $param?eval "q($param)":"");
+ my @param = split(/,/,$param);
+
+ if ($attr eq 'expr') {
+ $$handlerAttributes{'result'} = EXPR;
+ } elsif ($attr eq 'node') {
+ $$handlerAttributes{'result'} = NODE;
+ $$handlerAttributes{'nodename'} = $param[0] || 'value';
+ } elsif ($attr eq 'exprOrNode') {
+ $$handlerAttributes{'result'} = EXPRORNODE;
+ $$handlerAttributes{'nodename'} = $param[0] || 'value';
+ $$handlerAttributes{'resultparam'} = $param[1] || 'as';
+ $$handlerAttributes{'resultnode'} = $param[2] || 'node';
+ } elsif ($attr eq 'nodelist') {
+ $$handlerAttributes{'result'} = NODELIST;
+ $$handlerAttributes{'nodename'} = $param[0] || 'value';
+ } elsif ($attr eq 'exprOrNodelist') {
+ $$handlerAttributes{'result'} = EXPRORNODELIST;
+ $$handlerAttributes{'nodename'} = $param[0] || 'value';
+ $$handlerAttributes{'resultparam'} = $param[1] || 'as';
+ $$handlerAttributes{'resultnode'} = $param[2] || 'node';
+ } elsif ($attr eq 'struct') {
+ $$handlerAttributes{'result'} = STRUCT;
+ $$handlerAttributes{'namespace'} = $param[0];
+ } elsif ($attr eq 'stack') {
+ $$handlerAttributes{'stack'} = $param[0];
+ } elsif ($attr eq 'smart') {
+ $$handlerAttributes{'smart'} = 1;
+ $$handlerAttributes{'capture'} = 1;
+ } elsif ($attr eq 'nodeAttr') {
+ my %namespace;
+ while (@param > 1) {
+ my ($ns, $prefix, $name) = parse_namespace($param[0]);
+ $namespace{$prefix} = $ns if $ns and $prefix;
+ $param[0] = "{$namespace{$prefix}}$prefix:$name" if $prefix;
+ $$handlerAttributes{'resultattr'}{$param[0]} = $param[1];
+ shift @param; shift @param;
+ }
+ } elsif ($attr eq 'attrib') {
+ foreach my $param (@param) {
+ $$handlerAttributes{'attribs'}{$param} = undef;
+ }
+ } elsif ($attr eq 'child') {
+ foreach my $param (@param) {
+ $$handlerAttributes{'children'}{$param} = undef;
+ }
+ } elsif ($attr eq 'attribOrChild') {
+ foreach my $param (@param) {
+ $$handlerAttributes{'attribs'}{$param} = undef;
+ $$handlerAttributes{'children'}{$param} = undef;
+ }
+ } elsif ($attr eq 'childStruct') {
+ my $spec = $param[0];
+ #warn("parsing $spec");
+ $spec =~ s/\s+/ /g;
+ $spec =~ s/ ?{ ?/{/g;
+ $spec =~ s/ ?} ?/}/g;
+ $$handlerAttributes{'struct'} = parseChildStructSpec($spec,{});
+ #warn("parsed $param[0], got
".serializeChildStructSpec($$handlerAttributes{'struct'}));
+ die("childStruct parse error") unless
$$handlerAttributes{'struct'};
+ } elsif ($attr eq 'keepWhitespace') {
+ $$handlerAttributes{'keepWS'} = 1;
+ } elsif ($attr eq 'captureContent') {
+ $$handlerAttributes{'capture'} = 1;
+ } elsif ($attr eq 'compile') {
+ $$handlerAttributes{'compile'} = 1;
+ } elsif ($attr eq 'XSP' && $warn) {
+ $warn = 0;
+ $$handlerAttributes{'xsp'} = 1;
+ } else {
+ push @rest, $a;
+ $warn = 0;
+ }
+ warn("Please prefix your XSP attributes with 'XSP_' (${pkg}::${sub} :
$attr)") if $warn;
+ }
+ delete $handlerAttributes{$sub} if not keys %$handlerAttributes;
+ return @rest;
+}
+
+sub FETCH_CODE_ATTRIBUTES {
+ my ($pkg,$sub) = @_;
+ my @attr;
+ my $handlerAttributes = $handlerAttributes{$sub};
+ return () if !defined $handlerAttributes;
+ if (exists $$handlerAttributes{'result'}) {
+ if ($$handlerAttributes{'result'} == NODELIST) {
+ push @attr,
'XSP_nodelist'._makeAttributeQuoted($$handlerAttributes{'nodename'});
+ } elsif ($$handlerAttributes{'result'} == EXPRORNODELIST) {
+ push @attr,
'XSP_exprOrNodelist'._makeAttributeQuoted($$handlerAttributes{'nodename'},$$handlerAttributes{'resultparam'},$$handlerAttributes{'resultnode'});
+ } elsif ($$handlerAttributes{'result'} == NODE) {
+ push @attr,
'XSP_node'._makeAttributeQuoted($$handlerAttributes{'nodename'});
+ } elsif ($$handlerAttributes{'result'} == EXPRORNODE) {
+ push @attr,
'XSP_exprOrNode'._makeAttributeQuoted($$handlerAttributes{'nodename'},$$handlerAttributes{'resultparam'},$$handlerAttributes{'resultnode'});
+ } elsif ($$handlerAttributes{'result'} == EXPR) {
+ push @attr, 'XSP_expr';
+ } elsif ($$handlerAttributes{'result'} == STRUCT) {
+ push @attr, 'XSP_struct';
+ $attr[-1] .= _makeAttributeQuoted($$handlerAttributes{'namespace'})
+ if defined $$handlerAttributes{'namespace'};
+ }
+ }
+ push @attr,
'XSP_nodeAttr'._makeAttributeQuoted(%{$$handlerAttributes{'resultattr'}}) if
$$handlerAttributes{'resultattr'};
+ push @attr, 'XSP_stack'._makeAttributeQuoted($$handlerAttributes{'stack'})
if $$handlerAttributes{'stack'};
+ push @attr, 'XSP_smart' if $$handlerAttributes{'smart'};
+ push @attr, 'XSP_keepWhitespace' if $$handlerAttributes{'keepWS'};
+ push @attr, 'XSP_captureContent' if $$handlerAttributes{'capture'};
+ push @attr, 'XSP_compile' if $$handlerAttributes{'compile'};
+
+ push @attr,
'XSP_childStruct'._makeAttributeQuoted(serializeChildStructSpec($$handlerAttributes{'struct'},{}))
+ if ($$handlerAttributes{'struct'});
+
+ my (@attribs, @children, @both);
+ foreach my $param (keys %{$$handlerAttributes{'attribs'}}) {
+ if (exists $$handlerAttributes{'children'}{$param}) {
+ push @both, $param;
+ } else {
+ push @attribs, $param;
+ }
+ }
+ foreach my $param (keys %{$$handlerAttributes{'children'}}) {
+ if (!exists $$handlerAttributes{'attribs'}{$param}) {
+ push @children, $param;
+ }
+ }
+ push @attr, 'XSP_attrib'._makeAttributeQuoted(@attribs) if @attribs;
+ push @attr, 'XSP_child'._makeAttributeQuoted(@children) if @children;
+ push @attr, 'XSP_attribOrChild'._makeAttributeQuoted(@both) if @both;
+ push @attr, 'XSP' if [EMAIL PROTECTED];
+ return @attr;
+}
+
+sub import {
+ my $pkg = caller;
+ #warn("making $pkg a SimpleTaglib");
+ {
+ no strict 'refs';
+ *{$pkg.'::Handlers::MODIFY_CODE_ATTRIBUTES'} =
\&MODIFY_CODE_ATTRIBUTES;
+ *{$pkg.'::Handlers::FETCH_CODE_ATTRIBUTES'} = \&FETCH_CODE_ATTRIBUTES;
+ push @{$pkg.'::ISA'}, 'AxKit2::XSP::SimpleTaglib';
+
+ }
+ return undef;
+}
+
+# companions to start_expr
+
+sub start_expr {
+ my $e = shift;
+ my $cur = $e->{Current_Element};
+ my $rc = $e->start_expr(@_);
+ $e->{Current_Element} = $cur;
+ return $rc;
+}
+
+sub start_elem {
+ my ($e, $nodename, $attribs, $default_prefix, $default_ns) = @_;
+ my($ns, $prefix, $name) = parse_namespace($nodename);
+ #$prefix = $e->generate_nsprefix($ns) if $ns and not $prefix;
+ if (not defined $ns and not defined $prefix) {
+ $ns = $default_ns; $prefix = $default_prefix;
+ }
+ $name = $prefix.':'.$name if $prefix;
+ if ($ns) {
+ $e->append_to_script('{ my $elem =
$document->createElementNS('.makeSingleQuoted($ns).','.makeSingleQuoted($name).');');
+ }
+ else {
+ $e->append_to_script('{ my $elem =
$document->createElement('.makeSingleQuoted($name).');');
+ }
+ $e->append_to_script('$parent->appendChild($elem); $parent = $elem; }' .
"\n");
+ if ($attribs) {
+ while (my ($key, $value) = each %$attribs) {
+ start_attr($e, $key); $e->append_to_script('.'.$value);
end_attr($e);
+ }
+ }
+ $e->manage_text(0);
+}
+
+sub end_elem {
+ my ($e) = @_;
+ $e->append_to_script('$parent = $parent->getParentNode;'."\n");
+}
+
+sub start_attr {
+ my ($e, $attrname, $default_prefix, $default_ns) = @_;
+ my($ns, $prefix, $name) = parse_namespace($attrname);
+ #$prefix = $e->generate_nsprefix($ns) if $ns and not $prefix;
+ if (not defined $ns and not defined $prefix) {
+ $ns = $default_ns; $prefix = $default_prefix;
+ }
+ $name = $prefix.':'.$name if $prefix;
+
+ if ($ns and defined $prefix) {
+
$e->append_to_script('$parent->setAttributeNS('.makeSingleQuoted($ns).','.makeSingleQuoted($name).',
""');
+ }
+ else {
+
$e->append_to_script('$parent->setAttribute('.makeSingleQuoted($name).', ""');
+ }
+ $e->manage_text(0);
+}
+
+sub end_attr {
+ my ($e) = @_;
+ $e->append_to_script(');'."\n");
+}
+
+# global variables
+# FIXME - put into $e (are we allowed to?)
+
+my %structStack = ();
+my %frame = ();
+my @globalframe = ();
+my $structStack;
+my %stacklevel = ();
+my %stackcur = ();
+
+# generic tag handler subs
+
+sub set_attribOrChild_value__open {
+ my ($e, $tag) = @_;
+ $globalframe[0]{'capture'} = 1;
+ return '$attr_'.makeVariableName($tag).' = ""';
+}
+
+sub set_attribOrChild_value : XSP_keepWhitespace {
+ return '; ';
+}
+
+my @ignore;
+sub set_childStruct_value__open {
+ my ($e, $tag, %attribs) = @_;
+ my $var = '$_{'.makeSingleQuoted($tag).'}';
+ if ($$structStack[0][0]{'param'} && exists
$$structStack[0][0]{'param'}{$tag}) {
+ $e->append_to_script('.do {
$param_'.$$structStack[0][0]{'param'}{$tag}.' = ""');
+ $globalframe[0]{'capture'} = 1;
+ return '';
+ }
+ my $desc = $$structStack[0][0]{'sub'}{$tag};
+ if (!$desc) {
+ $desc = $$structStack[0][0]{'sub'}{'*'};
+ #warn("$tag desc: ".Data::Dumper::Dumper($desc));
+ }
+ die("Tag $tag not found in childStruct specification.") if (!$desc);
+ push(@ignore, 1), return '' if ($$desc{'type'} eq '!');
+ push @ignore, 0;
+ unshift @{$$structStack[0]},$desc;
+ if ($$desc{'param'}) {
+ $e->append_to_script("{ \n");
+ foreach my $key (keys %{$$desc{'param'}}) {
+ $_ = $$desc{'param'}{$key};
+ $e->append_to_script("my \$param_$_; ");
+ $e->append_to_script("\$param_$_ =
".makeSingleQuoted($attribs{$key}).'; ')
+ if exists $attribs{$key};
+ }
+ $e->append_to_script('local ($_) = ""; ');
+ $var = '$_';
+ }
+ if ($$desc{'type'} eq '@') {
+ $e->append_to_script("$var ||= []; push [EMAIL PROTECTED], ");
+ } else {
+ $e->append_to_script("$var = ");
+ }
+ if ($$desc{'sub'}) {
+ $e->append_to_script('do {');
+ $e->append_to_script('local (%_) = (); ');
+ foreach my $attrib (keys %attribs) {
+ next if $$desc{'sub'}{$attrib}{'type'} eq '%';
+ $e->append_to_script('$_{'.makeSingleQuoted($attrib).'} = ');
+ $e->append_to_script('[ ') if $$desc{'sub'}{$attrib}{'type'} eq
'@';
+ $e->append_to_script(makeSingleQuoted($attribs{$attrib}));
+ $e->append_to_script(' ]') if $$desc{'sub'}{$attrib}{'type'} eq
'@';
+ $e->append_to_script('; ');
+ }
+ my $textname = $$desc{'sub'}{''}{'name'};
+ if ($textname) {
+ $e->append_to_script(' $_{'.makeSingleQuoted($textname).'} = ""');
+ $globalframe[0]{'capture'} = 1;
+ }
+ } else {
+ $e->append_to_script('""');
+ $globalframe[0]{'capture'} = 1;
+ }
+ return '';
+}
+
+sub set_childStruct_value {
+ my ($e, $tag) = @_;
+ if ($$structStack[0][0]{'param'} && exists
$$structStack[0][0]{'param'}{$tag}) {
+ $e->append_to_script('; }');
+ return '';
+ }
+ my $desc = $$structStack[0][0];
+ my $ignore = pop @ignore;
+ return '' if ($ignore);
+ shift @{$$structStack[0]};
+ if ($$desc{'sub'}) {
+ $e->append_to_script(' \%_; }; ');
+ }
+ if ($$desc{'param'}) {
+ my $var = '$_{'.makeSingleQuoted($tag).'}';
+ for (0..(scalar(%{$$desc{'param'}})-1)) {
+ $var .= "{\$param_$_}";
+ }
+ if ($$desc{'type'} eq '@') {
+ $e->append_to_script("$var ||= []; push [EMAIL PROTECTED], [EMAIL
PROTECTED];");
+ } else {
+ $e->append_to_script("$var = \$_;");
+ }
+ $e->append_to_script(" }\n");
+ }
+ return '';
+}
+
+sub set_XmlSmart_value__open {
+ my ($e, $tag, %attribs) = @_;
+ $dumper->Values([\%attribs]);
+ return
'XML::Smart::Tree::_Start($xml_subtree_parser,'.makeSingleQuoted($tag).','.$dumper->Dumpxs().');'."\n";
+}
+
+sub set_XmlSmart_value : XSP_captureContent {
+ my ($e, $tag) = @_;
+ return 'XML::Smart::Tree::_Char($xml_subtree_parser,$_) if
(length($_));'."\n".
+
'XML::Smart::Tree::_End($xml_subtree_parser,'.makeSingleQuoted($tag).');"";'."\n";
+}
+
+
+# code called from compiled XSP scripts
+sub parse_namespace {
+ local( $_ ) = shift;
+
+ # These forms will return ns and prefix as follows:
+ # *1. {ns}prefix:name => ns specified, prefix specified (fully specified)
+ # *2a. {ns}name => ns specified, prefix undefined (generate prefix)
+ # 2b. {ns}:name => ns specified, prefix undefined (generate prefix)
+ # *3a. prefix:name => ns undefined, prefix specified (lookup ns)
+ # 3b. {}prefix:name => ns undefined, prefix specified (lookup ns)
+ # *4a. {}name => ns is '', prefix is '' (no ns)
+ # 4b. {}:name => ns is '', prefix is '' (no ns)
+ # 4c. :name => ns is '', prefix is '' (no ns)
+ # *5. name => ns undefined, prefix undefined (default ns)
+ # The canonical forms are starred.
+ # (Note that neither a ns of '0' nor a prefix of '0' is allowed;
+ # they will be treated as empty strings.)
+
+ # The following tests can be used:
+ # if $ns and $prefix => fully specified
+ # if $ns and not $prefix => generate prefix
+ # if not $ns and $prefix => lookup ns
+ # if not $ns and defined $ns => no ns
+ # if not defined $ns and not defined $prefix => default ns
+
+ # This pattern match will almost give the desired results:
+ my ($ns, $prefix, $name) = m/^(?:{(.*)})? (?:([^:]*):)? (.*)$/x;
+
+ # These cases are fine with the pattern match:
+ # 1. {ns}prefix:name => ns specified, prefix specified
+ # 2a. {ns}name => ns specified, prefix undefined
+ # 3a. prefix:name => ns undefined, prefix specified
+ # 4b. {}:name => ns is '', prefix is ''
+ # 5. name => ns undefined, prefix undefined
+
+ # These cases need to be adjusted:
+
+ # 2b. {ns}:name => ns specified, prefix '' <= actual result
+ # 2b. {ns}:name => ns specified, prefix undefined <= desired result
+ $prefix = undef if $ns and not $prefix;
+
+ # 3b. {}prefix:name => ns '', prefix specified <= actual result
+ # 3b. {}prefix:name => ns undefined, prefix specified <= desired result
+ $ns = undef if not $ns and $prefix;
+
+ # 4a. {}name, => ns is '', prefix undefined <= actual result
+ # 4a. {}name, => ns is '', prefix is '' <= desired result
+ $prefix = '' if not $prefix and defined $ns and $ns eq '';
+
+ # 4c. :name => ns undefined, prefix is '' <= actual result
+ # 4c. :name => ns is '', prefix is '' <= desired result
+ $ns = '' if not $ns and defined $prefix and $prefix eq '';
+
+ ($ns, $prefix, $name);
+}
+
+sub _lookup_prefix {
+ my ($ns, $namespaces) = @_;
+ my $i = 0;
+ foreach my $namespace (@$namespaces) {
+ my ($nsprefix, $nsuri) = @$namespace;
+ ++$i;
+ next unless $nsuri eq $ns;
+ #$nsprefix = "stlns$i" if $nsprefix eq '' and $nsuri ne '';
+ return $nsprefix;
+ }
+ #return "stlns$i";
+ return "";
+}
+
+sub _lookup_ns {
+ my ($prefix, $namespaces) = @_;
+ $prefix ||= '';
+ my $i = 0;
+ foreach my $namespace (@$namespaces) {
+ my ($nsprefix, $nsuri) = @$namespace;
+ #++$i;
+ next unless $nsprefix eq $prefix;
+ #$nsprefix = "stlns$i" if $nsprefix eq '' and $nsuri ne '';
+ return wantarray ? ($nsuri, $nsprefix) : $nsuri;
+ }
+ my ($nsprefix, $nsuri) = @{$namespaces->[-1]}; # default namespace
+ return wantarray ? ($nsuri, $nsprefix) : $nsuri;
+}
+
+
+sub xmlize {
+ my ($document, $parent, $namespaces, @data) = @_;
+ foreach my $data (@data) {
+ if (UNIVERSAL::isa($data,'XML::LibXML::Document')) {
+ $data = $data->getDocumentElement();
+ }
+ if (UNIVERSAL::isa($data,'XML::LibXML::Node')) {
+ $document->importNode($data);
+ $parent->appendChild($data);
+ next;
+ }
+ die 'data is not a hash ref or DOM fragment!' unless ref($data) eq
'HASH';
+ while (my ($key, $val) = each %$data) {
+ my $outer_namespaces_added = 0;
+ if (substr($key,0,1) eq '@') {
+ $key = substr($key,1);
+ die 'attribute value is not a simple scalar!' if ref($val);
+ next if $key =~ m/^xmlns(?::|$)/; # already processed these
+ my ($ns, $prefix, $name) = parse_namespace($key);
+ #$prefix = _lookup_prefix($ns, $namespaces) if $ns and not
$prefix;
+ $ns = _lookup_ns($prefix, $namespaces) if not $ns and $prefix;
+ $name = $prefix.':'.$name if $prefix;
+ if ($ns and $prefix) {
+ $parent->setAttributeNS($ns,$name,$val);
+ } else {
+ $parent->setAttribute($name,$val);
+ }
+ next;
+ }
+
+ my ($ns, $prefix, $name) = parse_namespace($key);
+ $prefix = _lookup_prefix($ns, $namespaces) if $ns and not $prefix;
+ if (defined $ns) {
+ unshift @$namespaces, [ $prefix => $ns ];
+ $outer_namespaces_added++;
+ }
+ my @data = ref($val) eq 'ARRAY'? @$val:$val;
+ foreach my $data (@data) {
+ my $namespaces_added = 0;
+ if (ref($data) and ref($data) eq 'HASH') {
+ # search for namespace declarations in attributes
+ while (my ($key, $val) = each %$data) {
+ if ($key =~ m/[EMAIL PROTECTED](?::|$)(.*)/) {
+ unshift @$namespaces, [ $1 => $val ];
+ $namespaces_added++;
+ }
+ }
+ }
+
+ my $elem;
+ if (length($key)) {
+ my($nsuri, $nsprefix, $local) = ($ns, $prefix, $name);
+ ($nsuri, $nsprefix) = _lookup_ns($nsprefix, $namespaces)
if not defined $nsuri;
+ $local = $nsprefix.':'.$local if $nsprefix;
+ if ($nsuri) {
+ $elem = $document->createElementNS($nsuri,$local);
+ } else {
+ $elem = $document->createElement($local);
+ }
+ $parent->appendChild($elem);
+ } else {
+ $elem = $parent;
+ }
+
+ if (ref($data)) {
+ xmlize($document, $elem, $namespaces, $data);
+ } else {
+ my $tn = $document->createTextNode($data);
+ $elem->appendChild($tn);
+ }
+ splice(@$namespaces, 0, $namespaces_added) if
$namespaces_added; # remove added namespaces
+ }
+ splice(@$namespaces, 0, $outer_namespaces_added) if
$outer_namespaces_added; # remove added namespaces
+ }
+ }
+}
+
+# event handlers
+
+sub characters {
+ my ($e, $node) = @_;
+ my $text = $node->{'Data'};
+ if ($globalframe[0]{'ignoreWS'}) {
+ $text =~ s/^\s*//;
+ $text =~ s/\s*$//;
+ }
+ return '' if $text eq '';
+ return '.'.makeSingleQuoted($text);
+}
+
+sub start_element
+{
+ my ($e, $element) = @_;
+ my %attribs = map { $_->{'Name'} => $_->{'Value'} }
@{$element->{'Attributes'}};
+ my $tag = $element->{'Name'};
+ #warn("Element: ".join(",",map { "$_ => ".$$element{$_} } keys %$element));
+ my $ns = $element->{'NamespaceURI'};
+ my $frame = ($frame{$ns} ||= []);
+ $structStack = ($structStack{$ns} ||= []);
+ my $rtpkg = $AxKit2::Transformer::XSP::tag_lib{$ns};
+ my $pkg = $rtpkg."::Handlers";
+ my ($sub, $subOpen, $rtsub, $rtsubOpen);
+ my $attribs = {};
+ my $longtag;
+ #warn("full struct:
".serializeChildStructSpec($$structStack[0][$#{$$structStack[0]}]{'sub'})) if
$$structStack[0];
+ #warn("current node: ".$$structStack[0][0]{'name'}) if $$structStack[0];
+ #warn("rest struct:
".serializeChildStructSpec($$structStack[0][0]{'sub'})) if $$structStack[0];
+ if ($$structStack[0][0]{'param'} && exists
$$structStack[0][0]{'param'}{$tag}) {
+ $sub = \&set_childStruct_value;
+ $subOpen = \&set_childStruct_value__open;
+ } elsif ($$structStack[0][0]{'sub'} && (exists
$$structStack[0][0]{'sub'}{$tag} || exists $$structStack[0][0]{'sub'}{'*'})) {
+ my $tkey = $tag;
+ $tkey = '*' if (!exists $$structStack[0][0]{'sub'}{$tag});
+ if ($$structStack[0][0]{'sub'}{$tkey}{'sub'}) {
+ foreach my $key (keys %{$$structStack[0][0]{'sub'}{$tkey}{'sub'}})
{
+ $$attribs{$key} = $attribs{$key} if exists $attribs{$key};
+ }
+ }
+ if ($$structStack[0][0]{'sub'}{$tkey}{'param'}) {
+ foreach my $key (keys
%{$$structStack[0][0]{'sub'}{$tkey}{'param'}}) {
+ $$attribs{$key} = $attribs{$key} if exists $attribs{$key};
+ }
+ }
+ $sub = \&set_childStruct_value;
+ $subOpen = \&set_childStruct_value__open;
+ } else {
+ for my $i (0..$#{$frame}) {
+ if (exists $$frame[$i]{'vars'}{$tag}) {
+ #warn("variable: $tag");
+ $sub = \&set_attribOrChild_value;
+ $subOpen = \&set_attribOrChild_value__open;
+ last;
+ }
+ }
+ if (!$sub) {
+ my @backframes = (reverse(map{ ${$_}{'name'} } @{$frame}),$tag);
+ #warn("frames: "[EMAIL PROTECTED]", backframes:
".join(",",@backframes));
+ my $i = @backframes+1;
+ while ($i) {
+ $longtag = join('___', @backframes) || '_default';
+ shift @backframes;
+ $i--;
+ #warn("checking for $longtag");
+ if ($sub = $pkg->can(makeVariableName($longtag))) {
+ $subOpen = $pkg->can(makeVariableName($longtag)."__open");
+ }
+ if ($handlerAttributes{$rtsub} and $rtsub =
$rtpkg->can(makeVariableName($longtag))) {
+ $rtsubOpen =
$rtpkg->can(makeVariableName($longtag)."__open");
+ }
+ die("Simultaneous run-time and compile-time handlers for one
tag not supported") if $sub and $rtsub;
+ last if $sub or $rtsub;
+ }
+ }
+ }
+ if (((!$sub && !$rtsub) || $longtag eq '_default') && $frame{smart}) {
+ $sub = &set_XmlSmart_value;
+ $subOpen = &set_XmlSmart_value__open;
+ }
+ die "invalid tag: $tag (namespace: $ns, package $pkg, parents ".join(",
",map{ ${$_}{'name'} } @{$frame}).")" unless $sub or $rtsub;
+
+ my $handlerAttributes = $handlerAttributes{$sub || $rtsub};
+ if ($$handlerAttributes{'compile'}) {
+ $sub = $rtsub;
+ undef $rtsub;
+ $subOpen = $rtsubOpen;
+ undef $rtsubOpen;
+ }
+
+ if ($$handlerAttributes{'result'} == STRUCT ||
!$$handlerAttributes{'result'} ||
+ $$handlerAttributes{'result'} == NODELIST ||
+ ($$handlerAttributes{'result'} == EXPRORNODELIST &&
+ $attribs{$$handlerAttributes{'resultparam'}} eq
+ $$handlerAttributes{'resultnode'})) {
+
+ # FIXME: this can give problems with non-SimpleTaglib-taglib
interaction
+ # it must autodetect whether to use '.do' or not like xsp:expr, but as
+ # that one doesn't work reliably neither, it probably doesn't make any
+ # difference
+ $e->append_to_script('.') if ($globalframe[0]{'capture'});
+ $e->append_to_script('do { ') if ($element->{Parent});
+
+ } elsif ($$handlerAttributes{'result'} == NODE ||
+ ($$handlerAttributes{'result'} == EXPRORNODE
+ && $attribs{$$handlerAttributes{'resultparam'}} eq
+ $$handlerAttributes{'resultnode'})) {
+
+ $e->append_to_script('.') if ($globalframe[0]{'capture'});
+ $e->append_to_script('do { ');
+
start_elem($e,$$handlerAttributes{'nodename'},$$handlerAttributes{'resultattr'},$element->{'Prefix'},$ns);
+ start_expr($e,$tag);
+ } else {
@@ Diff output truncated at 30000 characters. @@