#?SuikaWikiConfig/2.0 Plugin: @Name: SuikaWiki09 @Description: @@@: SuikaWiki/0.9 document format @@lang:en @License: %%Perl%% @Author: @@Name: @@@@: Wakaba @@@lang:ja @@@script:Latn @@Mail[list]: w@suika.fam.cx @Date.RCS: $Date: 2004/04/26 00:53:00 $ @RequiredPlugin[list]: Edit WikiFormCore WikiLinking WikiStruct @Use: use Message::Markup::XML::QName qw/NS_xml_URI/; my $Reg_Form_Content_M = qr{ \ \#form \ (?: \ \( (\w+) \) ## id \ )? \ : ' ((?>[^\\']*)(?>(?>[^\\']+|\\.)*)) ' ## input \ (?> : ' ((?>[^\\']*)(?>(?>[^\\']+|\\.)*)) ' ## template \ (?> : ' ((?>[^\\']*)(?>(?>[^\\']+|\\.)*)) ' )? )? ## option }x; my $Reg_Embed_Content_M = qr{ \ \#([a-z-]+) \ (?> \ \( (\w+) \) ## id \ )? \ (?> \ : ( \w+ (?> : \w+ )* ) ## parameter \ )? }x; my $Reg_URI_Opaque = qr{ \ (?>[^<>"]*) \ (?> \ (?> \ [^<>"]+ \ | "(?>[^"\\]*)(?>(?>[^"\\]+|\\.)*)" \ )* \ ) }x; my ($WIKIRESOURCE, $WIKISTRUCT, $WIKIFORMCORE, $WIKILINKING); PluginConst: @NS_SW09: urn:x-suika-fam-cx:markup:suikawiki:0:9: @NS_HTML3: urn:x-suika-fam-cx:markup:ietf:html:3:draft:00: @NS_XHTML1: http://www.w3.org/1999/xhtml @NS_XHTML2: http://www.w3.org/2002/06/xhtml2 @WIKIFORMCORE: {($WIKIFORMCORE ||= SuikaWiki::Plugin->module_package ('WikiFormCore'))} @WIKILINKING: {($WIKILINKING ||= SuikaWiki::Plugin->module_package ('WikiLinking'))} @WIKIRESOURCE: {($WIKIRESOURCE ||= SuikaWiki::Plugin->module_package ('WikiResource'))} @WIKISTRUCT: {($WIKISTRUCT ||= SuikaWiki::Plugin->module_package ('WikiStruct'))} Format: @ModuleName: SuikaWiki::V0 @Description: @@@: Dummy base format for SuikaWiki/0.* @@lang:en @Inherit[list]: Text::Plain Format: @Name: SuikaWiki @Version: 0.9 @Type: @@@: text/x-suikawiki @@version: 0.9 @ModuleName: SuikaWiki::V0_9 @Inherit[list]: SuikaWiki::V0 @Description: @@@: SuikaWiki/0.9 document format (Standard document format for SuikaWiki 2) @@lang:en @Use: use Message::Markup::XML::QName qw/NS_xml_URI/; use Message::Util::Error; @Converter: @@Type: text/html @@IsFragment: 1 @@Description: @@@@: Converting SuikaWiki/0.9 to Hypertext Markup Language fragment @@@lang:en @@Main: $opt->{o}->{wiki} ||= $self->{wiki}; ## Text format -> XML format my $xml = __FUNCPACK__->get_xml_tree (text => $source, opt => $opt, wiki => $self->{wiki}); ## SuikaWiki/0.9 -> XHTML 1 __FUNCPACK__->sw09_to_xhtml1 (source => $xml, parent => $opt->{-parent}, o => $opt->{o}, page => $opt->{page}); if ($opt->{-with_annotation_input}) { SuikaWiki::Plugin->module_package ('WikiFormCore') ->make_content_form_in_html ($opt->{-parent}, $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:footannotate:input', o => $opt->{o}, wiki => $opt->{o}->{wiki}), option => $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:footannotate:option', o => $opt->{o}, wiki => $opt->{o}->{wiki}), o => $opt->{o}, wiki => $opt->{o}->{wiki}, output => { page => $opt->{page}, }); } @Converter: @@Type: @@@@: application/x-suikawiki+xml @@@version: 0.9 @@Description: @@@@: Converting SuikaWiki/0.9 text format to XML format @@@lang: en @@Main: my $xml = __FUNCPACK__->get_xml_tree (text => $source, opt => $opt, wiki => $self->{wiki}); ## TODO: Make a clone $opt->{-parent}->append_node ($xml); @NextIndex: @@Name: anchor @@Main: my $xml = __FUNCPACK__->get_xml_tree (text => $source, opt => \%opt, wiki => $self->{wiki}); (__FUNCPACK__->get_last_anchor_index ($xml)) + 1; @WikiForm: @@Main: ## Text format -> XML format my $xml = __FUNCPACK__->get_xml_tree (text => $source, opt => \%opt, wiki => $self->{wiki}); local $opt{o}->{var}->{sw09__anchor_index}; local $opt{o}->{var}->{sw09__document_tree} = $xml; my $form; if ($opt{o}->{form}->{output}->{id}) { $form = __FUNCPACK__->get_element_by_id ($xml, $opt{o}->{form}->{output}->{id}); undef $form unless ref $form and $form->namespace_uri eq $NS_SW09 and $form->local_name eq 'form'; } else { $form = __FUNCPACK__->get_nth_element ($xml, $NS_SW09 => 'form', $opt{o}->{form}->{output}->{index}); } my $ref; if (ref $form) { $ref = $form->get_attribute_value ('ref', default => 'form'); } else { $ref = '#footannotate'; } ## WikiForm Option if ($ref eq 'form') { $opt{option} ||= $form->get_attribute_value ('option'); } elsif ($ref eq 'comment') { $opt{option} ||= $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:comment:option', o => $opt{o}, wiki => $opt{o}->{wiki}); } elsif ($ref eq '#footannotate') { $opt{option} ||= $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:footannotate:option', o => $opt{o}, wiki => $opt{o}->{wiki}); } else { ## TODO: } $WIKIFORMCORE->set_option ($opt{option} => $opt{o}) if $opt{option}; my @missing; for (keys %{$opt{o}->{form}->{require}->{id}}) { unless (length $opt{o}->{wiki}->{input}->parameter ($WIKIFORMCORE->control_id ($opt{o}, local_id => $_, local_id_prefix => 'wikiform__') ->{local_id})) { push @missing, $_; } } if (@missing) { return [{ type => 'required_param_missing', missing_id => \@missing, }]; } ## Replace Output Template my $result; if ($ref eq 'form') { $opt{template} ||= $form->get_attribute_value ('template', default => ''); } elsif ($ref eq 'comment') { $opt{template} ||= $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:comment:template', o => $opt{o}, wiki => $opt{o}->{wiki}); } elsif ($ref eq '#footannotate') { $opt{template} ||= $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:footannotate:template', o => $opt{o}, wiki => $opt{o}->{wiki}); } try { $result = SuikaWiki::Plugin->text_formatter ('form_template') ->replace ($opt{template}, param => $opt{o}); } catch Message::Util::Formatter::error with { my $err = shift; SuikaWiki::Plugin->module_package ('Error') ->reporting_formatting_template_error ($err, $err->{option}->{param}->{wiki}); ##TODO: throw SuikaWiki::View::Implementation::error -type => 'ERROR_REPORTED'; }; ## Insert if (length $result) { if ($ref eq '#footannotate') { my $parent; for (@{$xml->child_nodes}) { if ($_->node_type eq '#element' and $_->local_name eq 'document') { for (@{$_->child_nodes}) { if ($_->node_type eq '#element' and $_->local_name eq 'body') { $parent = $_; last; } } } } CORE::die "Buggy implementation: no body element".$xml unless ref $parent; $parent->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'text') ->append_text ($result); } else { my $parent = $form->parent_node; CORE::die "Byggy implementation: No parent of form" unless ref $parent; my $children = $parent->child_nodes; $result .= "\x0A" unless substr ($result, -1) eq "\x0A"; $parent->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'text') ->append_text ($result); my $node = pop @{$children}; my $form_str = overload::StrVal ($form); my $i = 0; for (@{$children}) { last if overload::StrVal ($_) eq $form_str; $i++; } if ($opt{o}->{form}->{output}->{reverse}) { splice @{$children}, $i + 1, 0, $node; } else { splice @{$children}, $i, 0, $node; } } } else { ## TODO: } ## XML format -> Text format my $text = __FUNCPACK__->xml_to_text ($xml, {%opt}); my %fragment = (fragment => $opt{o}->{form}->{output}->{id} || 'wikiform-'.$opt{o}->{form}->{output}->{index}); if (not $opt{o}->{form}->{output}->{reverse} and $opt{o}->{var}->{sw09__anchor_index}) { %fragment = (anchor_no => $opt{o}->{var}->{sw09__anchor_index}); } my $action = [ { type => 'write', content => $text, update_lastmodified => time, }, { type => 'ok', %fragment, }, ]; @HeadSummary: @@Main: my $xml = __FUNCPACK__->get_xml_tree (text => $source, opt => \%opt, wiki => $self->{wiki}); return $xml->inner_text; FormattingRule: @Category[list]:form-template @Name: index @Description: @@@: Next anchor index number @@lang:en @After: if ($o->{var}->{sw09__anchor_index}) { ++$o->{var}->{sw09__anchor_index}; } else { $o->{var}->{sw09__anchor_index} = 1 + __FUNCPACK__->get_last_anchor_index ($o->{var}->{sw09__document_tree}); } $p->{-result} .= $o->{var}->{sw09__anchor_index}; Function: @Name: get_last_anchor_index @Main: my (undef, $xml) = @_; my $anchor = 0; my $get_anchor_no; $get_anchor_no = sub { my $node = shift; for my $child (@{$node->child_nodes}) { my $nt = $child->node_type; if ($nt eq '#element') { if ($child->namespace_uri => $NS_SW09 and $child->local_name eq 'anchor-end') { my $a = $child->get_attribute_value ('anchor', default => 0, namespace_uri => $NS_SW09); $anchor = 0+$a if $anchor < 0+$a; } else { $get_anchor_no->($child); } } elsif ($nt eq '#document' or $nt eq '#fragment') { $get_anchor_no->($child); } } }; $get_anchor_no->($xml); $anchor; Function: @Name: get_xml_tree @Main: my (undef, %opt) = @_; if ($opt{opt}->{page}) { ## TODO: unless ($__FUNCPACK__::DBLoaded) { $opt{wiki}->{db}->_set_prop_db (sw09__xml_tree => {-db_open => sub { require SuikaWiki::DB::Hash; new SuikaWiki::DB::Hash; }}); $__FUNCPACK__::DBLoaded++; } my $xml = new Message::Markup::XML::Node type => '#fragment'; __FUNCPACK__->text_to_xml (${$opt{text}}, {%{$opt{opt}}, -parent => $xml}); $opt{wiki}->{db}->set (sw09__xml_tree => $opt{opt}->{page} => $xml); $xml; } else { my $xml = new Message::Markup::XML::Node type => '#fragment'; __FUNCPACK__->text_to_xml (${$opt{text}}, {%{$opt{opt}}, -parent => $xml}); $xml; } Function: @Name: sw09_to_xhtml1 @Main: my (undef, %opt) = @_; my ($apply_template, $apply_template_children); $apply_template_children = sub { for (@{$_[0]->child_nodes}) { $apply_template->($_ => $_[1]) unless $_->node_type eq '#attribute'; } }; $apply_template = sub { my ($source, $result) = @_; my $ln = $source->local_name; if ($source->node_type eq '#text') { $result->append_text ($source->inner_text); } elsif ({qw/code 1 samp 1 var 1 dfn 1 kbd 1 sub 1 sup 1/}->{$ln}) { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => $ln); my $class = $source->get_attribute_value ('class', default => ''); $node->set_attribute (class => $class) if $class; $apply_template_children->($source => $node); } elsif ({qw/ins 1 del 1 insert 1 delete 1/}->{$ln}) { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => {qw/ins ins insert ins delete del del del/}->{$ln}); my $class = $source->get_attribute_value ('class', default => ''); $node->set_attribute (class => $class) if $class; ## TODO: cite $apply_template_children->($source => $node); } elsif ({qw/table 1 tbody 1 tr 1 td 1 blockquote 1 ul 1 ol 1 li 1 pre 1 dl 1 dt 1 dd 1 em 1 strong 1/}->{$ln}) { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => $ln); if ($ln eq 'td') { my $colspan = $source->get_attribute_value ('colspan', default => 0); $node->set_attribute (colspan => $colspan) if $colspan; } elsif ($ln eq 'pre') { $node->set_attribute (space => 'preserve', namespace_uri => NS_xml_URI); my $class = $source->get_attribute_value ('class', default => ''); $node->set_attribute (class => $class) if length $class; } $apply_template_children->($source => $node); } elsif ($ln eq 'anchor') { local $opt{o}->{var}->{sw09__anchor_content} = sub { $apply_template_children->($source => shift); }; SuikaWiki::Plugin->module_package ('WikiLinking') ->to_wikipage_in_html ({ label => $WIKIRESOURCE->get_text (name => 'Link:SuikaWiki/0.9:toWikiPage:SourceLabel', param => $opt{o}, wiki => $opt{o}->{wiki}), } => { base => $opt{o}->{wiki}->{var}->{page}, page_name => $opt{o}->{wiki}->name ($source->inner_text) ->absolute (wiki => $opt{o}->{wiki}, nearest => 'content', base => $opt{o}->{wiki} ->{var}->{page}), page_anchor_no => $source->get_attribute_value ('anchor', namespace_uri => $NS_SW09), }, { o => $opt{o}, parent => $result, }); } elsif ($ln eq 'p') { $apply_template_children->($source => $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'p')); } elsif ($ln eq 'h') { my $node; if ($opt{o}->{var}->{ws__section_depth} > 6) { $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'div'); $node->set_attribute (class => 'heading h'.$opt{o}->{var} ->{ws__section_depth}); } else { $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'h'.$opt{o}->{var} ->{ws__section_depth}); } $apply_template_children->($source => $node); $WIKISTRUCT->set_section_id ($result, undef, $opt{o}->{wiki}, title => $source->inner_text); } elsif ($ln eq 'ruby' or $ln eq 'rubyb') { my @child; for (@{$source->child_nodes}) { if ({qw/rb 1 rt 1/}->{$_->local_name}) { push @child, $_; } } for ($result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'ruby')) { if ($ln eq 'rubyb') { my $class = join ' ', 'descriptive', split /\s+/, $source->get_attribute_value ('class', default => ''); $_->set_attribute (class => $class) if $class; } else { my $class = $source->get_attribute_value ('class', default => ''); $_->set_attribute (class => $class) if $class; } $apply_template_children->($child[0] => $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rb')); $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rp') ->append_text ('('); if ($child[1]) { $apply_template_children->($child[1] => $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rt')); } else { $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rt'); } if ($child[2]) { $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rp') ->append_text ('/'); $apply_template_children->($child[2] => $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rt')); } $_->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'rp') ->append_text (')'); } } elsif ($ln eq 'abbr') { my (@b); for (@{$source->child_nodes}) { push @b, $_ if {qw/rb 1 rt 1/}->{$_->local_name}; } my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'abbr'); $node->set_attribute (title => $b[1]->inner_text) if $b[1]; $apply_template_children->($b[0] => $node); } elsif ($ln eq 'q') { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'q'); ## TODO: cite $apply_template_children->($source => $node); } elsif ($ln eq 'weak') { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'span'); $node->set_attribute (class => 'weak'); $apply_template_children->($source => $node); } elsif ({qw/section 1 bodytext 1/}->{$ln}) { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'div'); $node->set_attribute (class => $ln); local $opt{o}->{var}->{ws__section_depth} = $opt{o}->{var}->{ws__section_depth} + 1; $apply_template_children->($source => $node); } elsif ($ln eq 'anchor-end') { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'a'); $node->set_attribute (id => 'anchor-'.$source->get_attribute_value ('anchor', default => '0', namespace_uri => $NS_SW09)); $node->set_attribute (name => 'anchor-'.$source->get_attribute_value ('anchor', default => '0', namespace_uri => $NS_SW09)) if $opt{o}->{wiki}->{var}->{client}->{downgrade}->{html_no_id}; $node->set_attribute (class => 'anchor'); $node->append_text ($source->inner_text); } elsif ($ln eq 'anchor-internal') { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'a'); $node->set_attribute (href => '#anchor-'.$source->get_attribute_value ('anchor', namespace_uri => $NS_SW09, default => '0')); $node->set_attribute (class => 'wiki-anchor'); $node->append_text ($source->inner_text); } elsif ($ln eq 'anchor-external') { local $opt{o}->{var}->{sw09__anchor_content} = sub { $apply_template_children->($source => shift); }; $WIKILINKING ->to_resource_in_html ( { label => $WIKIRESOURCE ->get_text (name => 'Link:SuikaWiki/0.9:toResource:SourceLabel', param => $opt{o}, wiki => $opt{o}->{wiki}), }, { resource_scheme => $source->get_attribute_value ('resScheme', namespace_uri => $NS_SW09, default => 'URI'), resource_parameter => $source->get_attribute_value ('resParameter', namespace_uri => $NS_SW09, default => ''), }, { o => $opt{o}, parent => $result, }); } elsif ($ln eq 'form') { my $ref = $source->get_attribute_value ('ref', default => 'form'); if ($ref eq 'form') { $WIKIFORMCORE->make_content_form_in_html ($result, $source->get_attribute_value ('input', default => ''), option => $source->get_attribute_value ('option'), name => $source->get_attribute_value ('id'), o => $opt{o}, wiki => $opt{o}->{wiki}, output => { page => $opt{page}, }); } elsif ($ref eq 'comment') { $WIKIFORMCORE->make_content_form_in_html ($result, $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:comment:input', o => $opt{o}, wiki => $opt{o}->{wiki}), option => $WIKIRESOURCE->get (name => 'SuikaWiki/0.9:form:comment:option', o => $opt{o}, wiki => $opt{o}->{wiki}), name => $source->get_attribute_value ('id'), o => $opt{o}, wiki => $opt{o}->{wiki}, output => { page => $opt{page}, }); } else { ## TODO: Warning $WIKIFORMCORE->make_content_form_in_html ($result, '', option => '', o => $opt{o}, wiki => $opt{o}->{wiki}, output => { page => $opt{page}, }); } } elsif ($ln eq 'dr') { $apply_template_children->($source => $result); } elsif ($ln eq 'document') { my $body; for (@{$source->child_nodes}) { $body = $_ and last if $_->local_name eq 'body'; } my $body_block = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'div'); $body_block->set_attribute (class => 'block SuikaWiki-0-9'); $apply_template_children->($body => $body_block); } else { my $node = $result->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'span'); $node->set_attribute (class => 'warn'); for ($node->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'ins') ->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'code')) { $_->set_attribute (class => 'XML element'); $_->append_text ("<".$source->namespace_uri.">:$ln"); } $apply_template_children->($source => $node); } }; $apply_template_children->($opt{source} => $opt{parent}); Function: @Name: xml_to_text @Main: my (undef, $src, $opt) = @_; my %is_block = ( qw/p 1 blockquote 1 pre 1 ul 1 ol 1 dl 1 section 1 h 1 bodytext 1 document 1 head 1 body 1 table 1 text 1 form 1 insert 1 delete 1/ ); my %x2t; %x2t = ( anchor => sub { my $source = shift; my $result = '[[' . $x2t{'#inline'}->($source, no_newline => 1) . ']'; my $anchor = $source->get_attribute_value ('anchor', namespace_uri => $NS_SW09, default => ''); if (length $anchor) { $result .= '>>'.(0+$anchor); } else { $anchor = $source->get_attribute_value ('resScheme', namespace_uri => $NS_SW09); if ($anchor) { my $param = $source->get_attribute_value ('resParameter', namespace_uri => $NS_SW09); if ($anchor eq 'URI' and $param =~ /^[0-9A-Za-z_+.%-]+:/) { $result .= '<' . $param . '>'; } else { $result .= '<' . $anchor . ':' . $param . '>'; } } } $result . ']'; }, li => sub { my $source = shift; my $result = ({qw/ul - ol =/}->{$opt->{o}->{var}->{sw09__list_type}} x $opt->{o}->{var}->{sw09__list_depth}) . ' ' . $x2t{'#flow'}->($source); $result; }, dt => sub { ':' . $x2t{'#inline'}->(return, no_newline => 1) . ':'; }, h => sub { ("*" x ($opt->{o}->{var}->{ws__section_depth} - 1)) . " " . $x2t{'#inline'}->(shift, no_newline => 1); }, 'anchor-end' => sub { return shift->inner_text; }, 'anchor-internal' => sub { return shift->inner_text; }, 'anchor-external' => sub { return '<'.shift->inner_text.'>'; }, form => sub { my $source = shift; my $ref = $source->get_attribute_value ('ref', default => 'form'); my $result = '[[#'.$ref; my $name = $source->get_attribute_value ('id'); $name =~ s/([()\\])/\\$1/g; $result .= '(' . $name . ')' if $name; ## General WikiForm if ($ref eq 'form') { $result .= ":'"; my $input = $source->get_attribute_value ('input', default => ''); $input =~ s/(['\\])/\\$1/g; $result .= $input . "':'"; my $template = $source->get_attribute_value ('template', default => ''); $template =~ s/(['\\])/\\$1/g; $result .= $template . "'"; my $option = $source->get_attribute_value ('option'); if ($option) { $option =~ s/(['\\])/\\$1/g; $result .= ":'" . $option . "'"; } ## Specific WikiForm } else { my $param = $source->get_attribute_value ('parameter'); if ($param) { $result .= ':' . $param; } } $result .= ']]'; }, pre => sub { my $source = shift; my $result = '[PRE'; my $class = $source->get_attribute_value ('class'); if ($class) { $class =~ s/([\\()])/\\$1/g; $result .= '(' . $class . ')'; } $result .= "[\x0A" . $x2t{'#inline'}->($source); $result .= "\x0A" unless substr ($result, -1) eq "\x0A"; $result .= "]PRE]\x0A"; }, insert => sub { my $source = shift; my $result = '[INS'; my $class = $source->get_attribute_value ('class'); if ($class) { $class =~ s/([\\()])/\\$1/g; $result .= '(' . $class . ')'; } local $opt->{o}->{var}->{sw09__list_depth} = 0; $result .= "[\x0A" . $x2t{'#block'}->($source); $result .= "\x0A" unless substr ($result, -1) eq "\x0A"; $result .= "]INS]\x0A"; }, delete => sub { my $source = shift; my $result = '[DEL'; my $class = $source->get_attribute_value ('class'); if ($class) { $class =~ s/([\\()])/\\$1/g; $result .= '(' . $class . ')'; } local $opt->{o}->{var}->{sw09__list_depth} = 0; $result .= "[\x0A" . $x2t{'#block'}->($source); $result .= "\x0A" unless substr ($result, -1) eq "\x0A"; $result .= "]DEL]\x0A"; }, document => sub { my $source = shift; my $result = '#?' . $source->get_attribute_value ('Name', namespace_uri => $NS_SW09, default => 'SuikaWiki') . '/' . $source->get_attribute_value ('Version', namespace_uri => $NS_SW09, default => '0.9'); for (@{$source->child_nodes}) { $result .= ($x2t{$_->local_name} or $x2t{'#undef'})->($_) if $_->node_type eq '#element'; } $result; }, head => sub { my $source = shift; my $result = ''; for (@{$source->child_nodes}) { if ($_->node_type eq '#element' and $_->local_name eq 'parameter') { $result .= ' '.$x2t{parameter}->($_); } } $result . "\x0A"; }, parameter => sub { my $source = shift; my $result = $source->get_attribute_value ('name', default => '') . '="'; my @v; for (@{$source->child_nodes}) { push @v, $x2t{value}->($_) if $_->node_type eq '#element' and $_->local_name eq 'value'; } $result .= join ',', @v; $result . '"'; }, value => sub { my $value = $x2t{'#inline'}->(shift, no_newline => 1); $value =~ s/(["\\])/\\$1/g; $value =~ tr/\x0A\x0D/ /; $value; }, section => sub { local $opt->{o}->{var}->{ws__section_depth} = $opt->{o}->{var}->{ws__section_depth} + 1; $x2t{'#block'}->(shift); }, body => sub { local $opt->{o}->{var}->{ws__section_depth} = 1; $x2t{'#block'}->(shift); }, text => sub { my ($source, %opt) = @_; my $result .= ''; for (@{$source->child_nodes}) { if ($_->node_type eq '#text') { $result .= $_->inner_text; } elsif ($_->node_type eq '#element') { $result .= ($x2t{$_->local_name} or $x2t{'#undef'})->($_); } } $result; }, dr => sub { my $result = $x2t{'#list'}->(shift); if ($result) { $result . "\x0A"; } else { "::\x0A"; } }, dt => sub { ':' . $x2t{'#inline'}->(shift, no_newline => 1) . ':'; }, dd => sub { $x2t{'#inline'}->(shift); }, tr => sub { my $result = $x2t{'#list'}->(shift); if ($result) { substr ($result, 1) . "\x0A"; } else { "',\x0A"; } }, td => sub { my $source = shift; my $result = $x2t{'#inline'}->($source, no_newline => 1); if ($result =~ /[,"\\]/ or $result =~ /==/) { $result =~ s/(["\\])/\\$1/g; $result = '"' . $result . '"'; } my $colspan = $source->get_attribute_value ('colspan', default => 1); $result .= ("\t,==" x ($colspan - 1)) if $colspan > 1; "\t," . $result; }, em => sub { "''" . $x2t{'#inline'}->($_, no_newline => 1) . "''"; }, strong => => sub { "'''" . $x2t{'#inline'}->($_, no_newline => 1) . "'''"; }, rb => sub { $x2t{'#inline'}->(shift, no_newline => 1); }, rt => sub { '] [' . $x2t{'#inline'}->(shift, no_newline => 1); }, replace => sub { '__&&' . shift->get_attribute_value ('by', default => '') . '&&__'; }, bodytext => sub { my ($source, %opt) = @_; local $opt->{o}->{var}->{sw09__bq_depth} = $opt->{o}->{var}->{sw09__bq_depth} + 1; my @result; for (@{$source->child_nodes}) { if ($_->node_type eq '#element') { my $ln = $_->local_name; push @result, [($x2t{$ln} or $x2t{'#undef'})->($_), $ln]; } } my $result = ''; my $prev = ''; for (@result) { my $s = $_->[0]; if ($_->[1] eq 'p') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; $result .= ('>' x $opt->{o}->{var}->{sw09__bq_depth}) . ' '; } elsif ($_->[1] eq 'form' or $_->[1] eq 'replace') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; $result .= ('>' x $opt->{o}->{var}->{sw09__bq_depth})."\x0A"; } elsif ($_->[1] eq 'blockquote' or $_->[1] eq 'text') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } else { unless ($prev eq 'text') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } $result .= ('>' x $opt->{o}->{var}->{sw09__bq_depth})."\x0A"; } $result .= $s; $prev = $_->[1]; } $result; }, ## Note: This element will be interpreted as a paragraph ## unless format is SuikaWikiImage/0.9. image => sub { my ($source, %opt) = @_; return "\x0A__IMAGE__\x0A" . $source->inner_text . "\x0A"; }, '#block' => sub { my ($source, %opt) = @_; my @result; for (@{$source->child_nodes}) { if ($_->node_type eq '#element') { my $ln = $_->local_name; push @result, [($x2t{$ln} or $x2t{'#undef'})->($_), $ln]; } } my $result = ''; my $prev = ''; for (@result) { my $s = $_->[0]; if ($_->[1] eq 'form') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; $result .= "\x0A"; } elsif ($_->[1] eq 'replace') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } elsif ($_->[1] eq 'text') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; $result .= "\x0A" if $prev eq 'p'; } else { if ($prev ne 'text' and $prev ne 'replace') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; $result .= "\x0A"; } } $result .= $s; $prev = $_->[1]; } $result; }, '#flow' => sub { my ($source, %opt) = @_; my @result; for (@{$source->child_nodes}) { if ($_->node_type eq '#element') { my $ln = $_->local_name; if ($is_block{$ln}) { push @result, [($x2t{$ln} or $x2t{'#undef'})->($_), $ln]; } else { if (@result and ($result[$#result]->[1] eq '#inline')) { $result[$#result]->[0] .= ($x2t{$ln} or $x2t{'#undef'})->($_); } else { push @result, [($x2t{$ln} or $x2t{'#undef'})->($_), '#inline']; } } } elsif ($_->node_type eq '#text') { if (@result and ($result[$#result]->[1] eq '#inline')) { $result[$#result]->[0] .= $_->inner_text; } else { push @result, [$_->inner_text, '#inline']; } } } my $result = ''; my $prev = ''; for (@result) { my $s = $_->[0]; if ($_->[1] eq '#inline') { if ($prev ne 'text' and $prev ne 'form' and $prev ne 'replace') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } $s =~ s/\x0D\x0A/\x0A/g; $s =~ s/\x0D/\x0A/g; $s =~ s/\x0A\x0A+/\x0A/g; $s =~ s/\x0A/\x20/g if $opt{no_newline}; } elsif ($_->[1] eq 'form' or $_->[1] eq 'replace') { if ($prev ne '#inline') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } } elsif ($_->[1] eq 'text') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } else { unless ($prev eq 'text') { $result .= "\x0A" if length $result and substr ($result, -1) ne "\x0A"; } } $result .= $s; $prev = $_->[1]; } $result; }, '#inline' => sub { my ($source, %opt) = @_; my $result .= ''; for (@{$source->child_nodes}) { if ($_->node_type eq '#text') { $result .= $_->inner_text; } elsif ($_->node_type eq '#element') { $result .= ($x2t{$_->local_name} or $x2t{'#undef'})->($_); } } $result =~ s/\x0D\x0A/\x0A/g; $result =~ s/\x0D/\x0A/g; $result =~ s/\x0A\x0A+/\x0A/g; $result =~ s/\x0A/\x20/g if $opt{no_newline}; $result; }, '#list' => sub { my ($source, %opt) = @_; my $result .= ''; for (@{$source->child_nodes}) { if ($_->node_type eq '#element') { $result .= ($x2t{$_->local_name} or $x2t{'#undef'})->($_); } } $result; }, '#undef' => sub { my $source = shift; ## TODO: "<".$source->namespace_uri.">:".$source->local_name . $x2t{'#inline'}->($source); }, ); for (qw/blockquote dl tbody table/) { $x2t{$_} = sub { $x2t{'#list'}->(shift) }; } for (qw/p dd/) { $x2t{$_} = sub { $x2t{'#flow'}->(shift) }; } for my $type (qw/ul ol/) { $x2t{$type} = sub { my $source = shift; local $opt->{o}->{var}->{sw09__list_type} = $type; local $opt->{o}->{var}->{sw09__list_depth} = $opt->{o}->{var}->{sw09__list_depth} + 1; my @result; for (@{$source->child_nodes}) { push @result, $x2t{$_->local_name}->($_) if $_->node_type eq '#element'; } my $result = ''; for (@result) { $result .= "\x0A" unless substr ($result, -1) eq "\x0A"; $result .= $_; } substr ($result, 1); }; } for my $type (qw/code samp var dfn kbd sub sup weak q ruby rubyb abbr ins del/) { $x2t{$type} = sub { my $source = shift; my $result = '['.uc $type; my $class = $source->get_attribute_value ('class', default => ''); if ($class) { $class =~ s/([()\\])/\\$1/g; $result .= '(' . $class . ')'; } $result .= '[' . $x2t{'#inline'}->($source, no_newline => 1) . ']'; my $anchor = $source->get_attribute_value ('anchor', namespace_uri => $NS_SW09, default => ''); if (length $anchor) { $result .= '>>'.(0+$anchor); } else { $anchor = $source->get_attribute_value ('resScheme', namespace_uri => $NS_SW09); if ($anchor) { my $param = $source->get_attribute_value ('resParameter', namespace_uri => $NS_SW09); if ($anchor eq 'URI' and $param =~ /^[0-9A-Za-z_+.%-]+:/) { $result .= '<' . $param . '>'; } else { $result .= '<' . $anchor . ':' . $param . '>'; } } } $result .= ']'; $result; }; } $x2t{'#list'}->($src); Function: @Name: get_nth_element @Main: my (undef, $node, $ns => $ln, $n) = @_; return $n if $n < 1; if ($node->node_type eq '#element' and $node->namespace_uri eq $ns and $node->local_name eq $ln) { return $node unless --$n; } for (@{$node->child_nodes}) { if ($_->node_type eq '#element') { if ($_->namespace_uri eq $ns and $_->local_name eq $ln) { return $_ unless --$n; } else { $n = __FUNCPACK__->get_nth_element ($_, $ns => $ln, $n); return $n if ref $n; } } elsif ($_->node_type eq '#fragment' or $_->node_type eq '#document') { $n = __FUNCPACK__->get_nth_element ($_, $ns => $ln, $n); return $n if ref $n; } } return $n; Function: @Name: get_element_by_id @Main: my (undef, $node, $id) = @_; return $node if $node->node_type eq '#element' and $node->get_attribute_value ('id', default_value => '') eq $id; for (@{$node->child_nodes}) { if ({'#element'=>1, '#fragment'=>1, '#document'=>1}->{$_->node_type}) { my $r = __FUNCPACK__->get_element_by_id ($_, $id); return $r if $r; } } Function: @Name: text_to_xml @Description: @@@: Converting SuikaWiki/0.9 text format to XML representation @@lang: en @Main: my (undef, $source, $opt) = @_; $source =~ s/\x0D\x0A/\x0A/g; $source =~ tr/\x0D/\x0A/; $source .= "\x0A"; my $root = $opt->{-parent} ->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'document'); my $head = $root->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'head'); $root->append_text ("\x0A"); my $body = $root->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'body'); $root->append_text ("\x0A"); if ($source =~ s#^\#\?(SuikaWiki(?:Image)?)/0\.9\b((?>.*))\s*##) { my $type = $1; my $param = $2; $root->set_attribute (Name => $type, namespace_uri => $NS_SW09); $root->set_attribute (Version => '0.9', namespace_uri => $NS_SW09); while ($param =~ /\G\s+([a-z-]+)="((?>[^"\\]*)(?>(?>[^"\\]+|\\.)*))"/g) { my ($name, $value) = ($1, $2); $value =~ s/\\(.)/$1/g; for ($head->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'parameter')) { $_->set_attribute (name => $name); for my $value (split /,/, $value) { $_->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'value') ->append_text ($value); } } $head->append_text ("\x0A"); } if ($type eq 'SuikaWikiImage') { $source =~ s/\x0A__IMAGE__\x0A(.*)$//s; if (my $image = $1) { $image =~ s/^\s+//; $image =~ s/\s+$//; $root->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'image') ->append_text ($image); $root->append_text ("\x0A"); } } } else { $root->set_attribute (Name => 'SuikaWiki', namespace_uri => $NS_SW09); $root->set_attribute (Version => '0.9', namespace_uri => $NS_SW09); ## TODO: warn } __FUNCPACK__->block_text_to_xml (\$source => $body, opt => $opt); Function: @Name:block_text_to_xml @Description: @@@: SuikaWiki/0.9 text format to XML representation convertion - block level elements @@lang:en @Main: my (undef, $source, $current, %opt) = @_; my %depth = %{$opt{depth} || {}}; my $back_to_section = sub { my $cur_type = $current->local_name; while (not ( $cur_type eq 'section' or $cur_type eq 'body' or $cur_type eq 'bodytext' or $cur_type eq 'insert' or $cur_type eq 'delete' ) ) { $current = $current->parent_node; $cur_type = $current->local_name; } delete $depth{list}; }; my $back_to_real_section = sub { my $cur_type = $current->local_name; while (not ( $cur_type eq 'section' or $cur_type eq 'body' or $cur_type eq 'insert' or $cur_type eq 'delete' ) ) { $current = $current->parent_node; $cur_type = $current->local_name; } delete $depth{bq}; delete $depth{list}; }; while ($$source =~ /\G([^\x0A]*)\x0A/gc) { my $line = $1; if ($line eq '') { $back_to_real_section->(); } elsif ($line =~ s/^([-=]+)\s*//) { my $list_type = substr ($1, -1) eq '-' ? 'ul' : 'ol'; my $depth = length $1; my $parent_type = $current->parent_node->local_name; ## Parent node is list element if ($parent_type eq 'ul' or $parent_type eq 'ol') { if ($depth{list} == $depth) { if ($parent_type eq $list_type) { $current = $current->parent_node; } else { $current = $current->parent_node ->parent_node ->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => $list_type); } } elsif ($depth < $depth{list}) { for ($depth+1..$depth{list}) { $current = $current->parent_node->parent_node; } $current = $current->parent_node; if ($current->local_name ne $list_type) { $current = $current->parent_node ->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => $list_type); } $depth{list} = $depth; } else { # $depth{list} < $depth $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => $list_type); $depth{list}++; } ## Parent node is non-list element } else { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => $list_type); $depth{list} = 1; } $current->append_text ("\x0A".(" " x $depth{list})); $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'li'); __FUNCPACK__->inline_text_to_xml (\$line => $current, %opt); } elsif ($line =~ s/^(\*+)\s*//) { my $depth = length $1; $back_to_real_section->(); if ($depth <= $depth{section}) { for ($depth..$depth{section}) { $back_to_real_section->(); $current = $current->parent_node; } $depth{section} = $depth; } else { # $depth{section} < $depth for ($depth{section}+2..$depth) { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'section'); } $depth{section} = $depth; } $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'section'); __FUNCPACK__->inline_text_to_xml (\$line => $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'h'), %opt, ); } elsif ($line =~ s/^(?!>>[0-9])(>+)\s*//) { my $depth = length $1; if ($depth <= $depth{bq}) { for ($depth+1..$depth{bq}) { $back_to_section->(); $current = $current->parent_node->parent_node; } $back_to_section->(); $current->append_text ("\x0A"); $depth{bq} = $depth; } else { # $depth{bq} < $depth $back_to_section->(); for ($depth{bq}+1..$depth) { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'blockquote') ->append_new_node (type => '#element', namespace_uri => $NS_HTML3, local_name => 'bodytext'); $current->append_text ("\x0A"); } $depth{bq} = $depth; } if (length $line) { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'p'); __FUNCPACK__->inline_text_to_xml (\$line => $current, %opt); } } elsif ($line =~ s/^(?>:\s*)([^:]+?)\s*:\s*//) { my $parent_type = $current->local_name; if ($parent_type eq 'dd') { $current = $current->parent_node->parent_node; $current->append_text ("\x0A"); } else { #if ($parent_type ne 'dl') { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'dl'); } $current = $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'dr'); __FUNCPACK__->inline_text_to_xml (\"$1" => $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'dt'), %opt, ); $current->append_text ("\x0A"); $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'dd'); __FUNCPACK__->inline_text_to_xml (\$line => $current, %opt); } elsif ($line =~ /^\[(INS|DEL)(?>(\([^()\\]*\))?)\[\s*$/) { $current->append_text ("\x0A"); my $mod = $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => {qw/INS insert DEL delete/}->{$1}); $mod->set_attribute (class => $2) if $2; __FUNCPACK__->block_text_to_xml ($source => $mod, %opt, 'return_by_'.$1 => 1, depth => \%depth); } elsif ($line =~ /^\](INS|DEL)\]\s*$/) { if ($opt{'return_by_'.$1}) { return; } else { ## TODO: warn } } elsif ($line =~ /^\[PRE(?>(?>\(((?>[^()\\]*)(?>(?>[^()\\]+|\\.)*))\))?)\[\s*$/) { $current->append_text ("\x0A"); my $pre = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'pre'); $pre->set_attribute (class => $1) if $1; $pre->set_attribute (space => 'preserve', namespace_uri => NS_xml_URI); my $f = 1; while ($$source =~ /\G([^\x0A]*)\x0A/gc) { my $line = $1; if ($line =~ /^\]PRE\]\s*$/) { undef $pre; last; } else { $f ? undef $f : $pre->append_text ("\x0A"); __FUNCPACK__->inline_text_to_xml (\$line => $pre, %opt); } } if (ref $pre) { # warn unmatched start-tag } } elsif ($line =~ /^\s/) { $current->append_text ("\x0A"); my $pre = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'pre'); $pre->set_attribute (space => 'preserve', namespace_uri => NS_xml_URI); __FUNCPACK__->inline_text_to_xml (\$line => $pre, %opt); while ($$source =~ /\G([^\x0A]*)\x0A/gc) { my $line = $1; if (length $line == 0) { pos ($$source) -= 1; last; } elsif ($opt{return_by_INS} and $line =~ /^\]INS\]\s*$/) { return; } elsif ($opt{return_by_DEL} and $line =~ /^\]DEL\]\s*$/) { return; } else { $pre->append_text ("\x0A"); __FUNCPACK__->inline_text_to_xml (\$line => $pre, %opt); } } } elsif ($line =~ /^,/) { $current->append_text ("\x0A"); my $tbody = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'table') ->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'tbody'); __FUNCPACK__->tablerow_text_to_xml (\$line => $tbody, %opt); while ($$source =~ /\G(,[^\x0A]*)\x0A/gc) { __FUNCPACK__->tablerow_text_to_xml (\"$1" => $tbody, %opt); } } else { my $current_type = $current->local_name; if ($current_type eq 'section' or $current_type eq 'body' or $current_type eq 'bodytext' or $current_type eq 'insert' or $current_type eq 'delete') { $current->append_text ("\x0A"); if ($line =~ s/^__&&([^&]+)&&__//) { $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'replace') ->set_attribute (by => $1); } elsif ($line =~ s/^\[\[$Reg_Form_Content_M\]\]//o) { for ($current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'form')) { $_->set_attribute (id => $1) if $1; my ($i, $t, $o) = ($2, $3 || '', $4 || ''); s/\\(.)/$1/g for ($i, $t, $o); $_->set_attribute (input => $i); $_->set_attribute (template => $t); $_->set_attribute (option => $o); } } elsif ($line =~ s/^\[\[$Reg_Embed_Content_M\]\]//o) { for ($current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'form')) { $_->set_attribute (ref => $1); $_->set_attribute (id => $2) if $2; $_->set_attribute (parameter => $3) if defined $3; } } if (length $line) { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'p'); __FUNCPACK__->inline_text_to_xml (\$line => $current, %opt); } } else { $current->append_text ("\x0A"); # replacement of prev.line's \n __FUNCPACK__->inline_text_to_xml (\$line => $current, %opt); } } } if ($opt{return_by_INS} or $opt{return_by_DEL}) { # warn } Function: @Name: tablerow_text_to_xml @Description: @@@: SuikaWiki/0.9 text format to XML representation - table row @@lang:en @Main: my (undef, $source => $current, %opt) = @_; $current->append_text ("\x0A"); $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'tr'); my $prev_cell; while ($$source =~ /\G,\s*/gc) { $$source =~ /\G([^,"][^,]*|"(?>[^"\\]*)(?>(?>[^"\\]+|\\.)*)"\s*)/gc; my $cell = $1; if ($cell =~ s/^"//) { $cell =~ s/"\s*$//g; $cell =~ s/\\(.)/$1/g; } else { $cell =~ s/\s+$//g; if ($cell eq '==') { if (ref $prev_cell) { $prev_cell->set_attribute (colspan => $prev_cell->get_attribute_value ('colspan', default => 1) + 1); next; } else { # TODO: warn } } } $prev_cell = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => 'td'); __FUNCPACK__->inline_text_to_xml (\$cell => $prev_cell, %opt); } # TODO: warn Function: @Name: inline_text_to_xml @Description: @@@: SuikaWiki/0.9 text format to XML representation - inline level elements @@lang:en @Main: my (undef, $source => $current, %opt) = @_; my $ElementDef = { ABBR => {ln => 'abbr', ns_uri => $NS_XHTML2}, CODE => {ln => 'code', ns_uri => $NS_XHTML2}, DEL => {ln => 'del', ns_uri => $NS_XHTML1}, DFN => {ln => 'dfn', ns_uri => $NS_XHTML2}, INS => {ln => 'ins', ns_uri => $NS_XHTML1}, KBD => {ln => 'kbd', ns_uri => $NS_XHTML2}, Q => {ln => 'q', ns_uri => $NS_XHTML1}, RUBY => {ln => 'ruby', ns_uri => $NS_XHTML2}, RUBYB => {ln => 'rubyb', ns_uri => $NS_SW09}, SAMP => {ln => 'samp', ns_uri => $NS_XHTML2}, SUB => {ln => 'sub', ns_uri => $NS_XHTML2}, SUP => {ln => 'sup', ns_uri => $NS_XHTML2}, VAR => {ln => 'var', ns_uri => $NS_XHTML2}, WEAK => {ln => 'weak', ns_uri => $NS_SW09}, anchor => {ln => 'anchor', ns_uri => $NS_SW09, has_fragment_no => 1}, del => {has_cite => 1}, ins => {has_cite => 1}, q => {has_cite => 1}, rb => {ln => 'rb', ns_uri => $NS_XHTML2, is_nested => 1}, rt => {ln => 'rt', ns_uri => $NS_XHTML2, is_nested => 1}, }; if ($$source =~ /\G\[([0-9]+)\]/gc) { for ($current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'anchor-end')) { $_->set_attribute (anchor => 0+$1, namespace_uri => $NS_SW09); $_->append_text ('['.$1.']'); } } my $depth = 0; while (pos $$source < length $$source) { if ($$source =~ /\G\[\[(?=\#)/gc) { my $form = $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'form'); if ($$source =~ /\G$Reg_Form_Content_M\]\]/ogc) { $form->set_attribute (id => $1) if $1; my ($i, $t, $o) = ($2, $3, $4); s/\\(.)/$1/g for ($i, $t, $o); $form->set_attribute (input => $i); $form->set_attribute (template => $t); $form->set_attribute (option => $o); } elsif ($$source =~ /\G$Reg_Embed_Content_M\]\]/ogc) { $form->set_attribute (ref => $1); $form->set_attribute (id => $2) if $2; $form->set_attribute (parameter => $3) if defined $3; } else { ## TODO: error SuikaWiki::Plugin->module_package('Error')->report_error_simple ($opt{opt}->{o}->{wiki}, InvalidForm => substr ($$source, pos ($$source))); } } elsif ($$source =~ /\G\[(?>([A-Z]+)(?>\(((?>[^()\\]*)(?>(?>[^()\\]+|\\.)*))\))?)?\[/gc) { my $type = $1 || 'anchor'; my $param = $2; my $def = $ElementDef->{ $type }; unless ($def) { ## TODO: error $def = $ElementDef->{CODE}; } $current = $current->append_new_node (type => '#element', namespace_uri => $def->{ns_uri}, local_name => $def->{ln}); $current->set_attribute (class => $param) if $param; if ($type eq 'RUBY' or $type eq 'RUBYB' or $type eq 'ABBR') { $current = $current->append_new_node (type => '#element', namespace_uri => $ElementDef->{rb}->{ns_uri}, local_name => $ElementDef->{rb}->{ln}); } $depth++; } elsif ($$source =~ /\G\](?> <([0-9A-Za-z_+.%-]+):($Reg_URI_Opaque)> \ | >>([0-9]+) )? \ \]/gcox) { my ($scheme, $opaque, $anchor) = ($1, $2, $3); unless ($depth) { $current->append_text (substr ($$source, $-[0], $+[0]-$-[0])); next; } my $def = $ElementDef->{$current->local_name} || {}; if (defined $anchor) { $current->set_attribute (anchor => $anchor + 0, namespace_uri => $NS_SW09); } elsif (defined $scheme) { if ($scheme =~ /[A-Z]/) { $current->set_attribute (resScheme => $scheme, namespace_uri => $NS_SW09); $current->set_attribute (resParameter => $opaque, namespace_uri => $NS_SW09); } else { $current->set_attribute (resScheme => 'URI', namespace_uri => $NS_SW09); $current->set_attribute (resParameter => "$scheme:$opaque", namespace_uri => $NS_SW09); } } $current = $current->parent_node; $current = $current->parent_node if $def->{is_nested}; $depth--; } elsif ($$source =~ /\G\]\s*\[/gc) { if ($current->local_name eq 'rb' or $current->local_name eq 'rt') { $current = $current->parent_node ->append_new_node (type => '#element', namespace_uri => $ElementDef->{rt}->{ns_uri}, local_name => $ElementDef->{rt}->{ln}); } else { $current->append_text (substr ($$source, $-[0], $+[0]-$-[0]-1)); pos ($$source)--; } } elsif ($$source =~ /\G'''?/gc) { my $type = $+[0] - $-[0] == 3 ? 'strong' : 'em'; if ($current->local_name eq $type) { $current = $current->parent_node; } else { $current = $current->append_new_node (type => '#element', namespace_uri => $NS_XHTML2, local_name => $type); } } elsif ($$source =~ /\G<([0-9A-Za-z_+.%-]+):($Reg_URI_Opaque)>/gco) { my ($scheme, $data) = ($1, $2); my $link = $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'anchor-external'); if (substr ($scheme, 0, 1) =~ /[A-Z]/) { $link->set_attribute (resScheme => $scheme, namespace_uri => $NS_SW09); $link->set_attribute (resParameter => $data, namespace_uri => $NS_SW09); } else { # URI Reference $link->set_attribute (resScheme => 'URI', namespace_uri => $NS_SW09); $link->set_attribute (resParameter => $scheme.':'.$data, namespace_uri => $NS_SW09); } $link->append_text ($scheme.':'.$data); } elsif ($$source =~ /\G__&&/gc) { if ($$source =~ /\G([^&]+)&&__/gc) { $current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'replace') ->set_attribute (by => $1); } else { $current->append_text ('__&&'); } } elsif ($$source =~ /\G((?> [^'\[\]<>_]+ | ' (?!') | \[ (?!\[|[A-Z]+(?>\([^()\\]* (?>[^()\\]+|\\.)*\))?\[) | \] (?! \] | >>[0-9]+\] | <[0-9A-Za-z_+.%-]+:$Reg_URI_Opaque>\] | \s*\[ ) | < (?![0-9A-Za-z_+.%-]+:$Reg_URI_Opaque>) | > (?!>[0-9]) | _ (?!_&&) )+)/oxgc) { $current->append_text ($1); } elsif ($$source =~ /\G>>([0-9]+)/gc) { for ($current->append_new_node (type => '#element', namespace_uri => $NS_SW09, local_name => 'anchor-internal')) { $_->set_attribute (anchor => 0+$1, namespace_uri => $NS_SW09); $_->append_text ('>>'.$1); } } else { CORE::die "Implementation buggy: ", substr ($$source, pos $$source); } } FormattingRule: @Category[list]: page-link link-to-resource @Name: sw09--link-anchor-content @Description: @@@: Output content of the anchor element @@lang:en @Formatting: if ($o->{var}->{sw09__anchor_content}) { $o->{var}->{sw09__anchor_content}->($p->{-parent}); } else { $WIKIRESOURCE->append_tree (name => 'Link:SuikaWiki/0.9:link-anchor-content:InvalidContext', param => $o, -parent => $p->{-parent}, wiki => $o->{wiki}); } Resource: @Link:SuikaWiki/0.9:link-anchor-content:InvalidContext: @@@: %percent;sw09--link-anchor-content; cannot be used in this context. @@lang:en @Link:SuikaWiki/0.9:toResource:SourceLabel: @@@: %select_link_resource_scheme ( URI => {<%link-to-it( label=>{%link-resource-parameters;}p, );>}, MAIL => {<%link-to-it( label => {%link-resource-parameters;}p, description => {%res (name=>{Link:MailAddress=});<%link-resource-parameters;>}p, );>}, otherwise => {<%link-to-it( label => {%sw09--link-anchor-content;}p, description => {%res (name=>{Link:URIReference=});<%uri-reference;>}p, );>}, ); @@lang:en @Link:SuikaWiki/0.9:toWikiPage:SourceLabel: @@@: %link-to-it( label=>{%sw09--link-anchor-content;%if-linked-wikipage-exist( true=>{%if-link-has-dest-anchor-no(true=>{>>%link-dest-anchor-no;});}, false=>{%res(name=>{Link:toWikiPage:NotExist:Mark});} );}p, description=>{%page-name(absolute);; %if-linked-wikipage-exist( true=>{%page-headline;}, false=>{(%res(name=>{Link:toWikiPage:NotExist:Description});)}, );}p, class=>{%if-linked-wikipage-exist(false=>{not-exist});}p, ); @SuikaWiki/0.9:form:comment:input: %line (content => {%textarea (id=>msg,size=>20,lines=>3);}p); %line (content => { (%text (description => {%res (name => {Form:Description:HumanName});}p, id => name, size => 6); [%text (description => {%res (name => {Form:Description:MailAddress});}p, id => mail, size => 5);] %check (default, id => record-date, label => {%res (name => {Form:Label:LogDate});}p, description => {%res (name => {Form:Description:LogDate});}p);) %submit (label => {%res (name => {Form:Label:Add});}p, description => {%res (name => {Form:Description:Add});}p); %we--update-lastmodified-datetime; }p); @SuikaWiki/0.9:form:comment:template: %n ;[%index;]%n ;%text(source=>msg);%n;(%name;%text(source=>mail,prefix=>" [",suffix=>"]");%iif(source=>record-date,true=>" [WEAK[%date;]]");)%n; @SuikaWiki/0.9:form:comment:option: %require (msg); @SuikaWiki/0.9:form:footannotate:input: %line (content => {%textarea (id=>msg,size=>20,lines=>3);}p); %line (content => { (%text (description => {%res (name => {Form:Description:HumanName});}p, id => name, size => 6); [%text (description => {%res (name => {Form:Description:MailAddress});}p, id => mail, size => 5);] %check (default, id => record-date, label => {%res (name => {Form:Label:LogDate});}p, description => {%res (name => {Form:Description:LogDate});}p);) %submit (label => {%res (name => {Form:Label:Add});}p, description => {%res (name => {Form:Description:Add});}p); %we--update-lastmodified-datetime; }p); @SuikaWiki/0.9:form:footannotate:template: %n ;[%index;]%n ;%text(source=>msg);%n ;(%name;%text(source=>mail,prefix=>" [",suffix=>"]");%iif(source=>record-date,true=>" [WEAK[%date;]]");)%n; @SuikaWiki/0.9:form:footannotate:option: %require (msg); @WikiFormat:MediaType:Description:IMT:text/x-suikawiki;version="0.9"##: @@@: SuikaWiki/0.9 (text format), as used in SuikaWiki 2 @@lang: en @WikiFormat:MediaType:Label:IMT:text/x-suikawiki;version="0.9"##: @@@: SuikaWiki/0.9 (text format) @@lang: en @WikiFormat:MediaType:Description:MAGIC:SuikaWiki/0.9##: @@@: SuikaWiki/0.9 (text format), as used in SuikaWiki 2 @@lang: en @WikiFormat:MediaType:Label:MAGIC:SuikaWiki/0.9##: @@@: SuikaWiki/0.9 (text format) @@lang: en Error: @Name: text_parse @Definition: @@INLINE_NO_CLOSE_TAG: @@@description: Close tag of element "%t (name => element_type);" not found. @@@level: non-fatal @@BLOCK_NO_CLOSE_TAG: @@@description: Close tag of element "%t (name => element_type);" not found. @@@level: non-fatal @@INVALID_FORM: @@@description: Invalid syntax of WikiForm @@@level: non-fatal Error: @Name: xml_to_text @IsA[list]: ::SuikaWiki::Format:: @Definition: @@