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. @@

Reply via email to