Shlomi Fish avatar Shlomi Fish committed 01bb3de Merge

Merge from make_Role_XSLT_parameterized.

Comments (0)

Files changed (10)

XML-GrammarBase/Build.PL

     license             => 'mit',
     dist_author         => q{Shlomi Fish <shlomif@cpan.org>},
     dist_version_from   => 'lib/XML/GrammarBase.pm',
+    configure_requires => {
+        'Module::Build' => '0.36',
+    },
     requires => {
         'autodie' => 0,
         'File::ShareDir' => 0,
         'MooX' => 0,
         'MooX::late' => 0,
         'MooX::Types::MooseLike' => 0,
+        'Package::Variant' => 0,
         'strict' => 0,
         'warnings' => 0,
         'XML::LibXML' => '2.0013',

XML-GrammarBase/MANIFEST

 Build.PL
 Changes
+MANIFEST
+META.json
+META.yml
+Makefile.PL
+README
+TODO.pod
 inc/Test/Run/Builder.pm
 lib/XML/GrammarBase.pm
 lib/XML/GrammarBase/Role/DataDir.pm
 lib/XML/GrammarBase/Role/RelaxNG.pm
 lib/XML/GrammarBase/Role/XSLT.pm
-Makefile.PL
-MANIFEST
-META.yml
-README
+lib/XML/GrammarBase/Role/XSLT/Global.pm
 t/00-load.t
+t/data/fiction-xml-invalid-test.xml
+t/data/fiction-xml-test-docbook-xslt-output.docbook.xml
+t/data/fiction-xml-test-html-xslt-output.xhtml
+t/data/fiction-xml-test.xml
+t/data/fiction-xml-to-docbook.xslt
+t/data/fiction-xml-to-html.xslt
+t/data/fiction-xml.rng
 t/data/screenplay-xml/xml/with-tags-inside-paragraphs.xml
-t/data/fiction-xml.rng
-t/data/fiction-xml-invalid-test.xml
-t/data/fiction-xml-test.xml
-t/data/fiction-xml-test-html-xslt-output.xhtml
-t/data/fiction-xml-to-html.xslt
+t/multi-xslt.t
 t/pod-coverage.t
 t/pod.t
 t/rng.t
 t/xslt.t
-META.json
-TODO.pod

XML-GrammarBase/lib/XML/GrammarBase/Role/DataDir.pm

 
 sub _undefize
 {
+    my $class = shift;
     my $v = shift;
 
     return defined($v) ? $v : "(undef)";

XML-GrammarBase/lib/XML/GrammarBase/Role/RelaxNG.pm

     else
     {
         confess "RelaxNG validation failed [\$ret_code == "
-            . _undefize($ret_code) . " ; $@]"
+            . $self->_undefize($ret_code) . " ; $@]"
             ;
     }
 

XML-GrammarBase/lib/XML/GrammarBase/Role/XSLT.pm

 
 =head1 NAME
 
-XML::GrammarBase::Role::XSLT - role for an XSLT converter.
+XML::GrammarBase::Role::XSLT - a parameterized role for a XSLT conversions.
 
 =head1 VERSION
 
 
 =cut
 
-use Moo::Role;
+use Package::Variant
+    importing => ['MooX::Role' => ['late'],],
+    subs => [ qw(has with) ];
 
-use MooX 'late';
+# use MooX 'late';
 
 use XML::LibXML;
 use XML::LibXSLT;
 
 our $VERSION = '0.0.1';
 
-with ('XML::GrammarBase::Role::RelaxNG');
 
-has 'xslt_transform_basename' => (isa => 'Str', is => 'rw');
-has '_stylesheet' => (isa => "XML::LibXSLT::StylesheetWrapper", is => 'rw');
-has '_xml_parser' => (
-    isa => "XML::LibXML",
-    is => 'rw',
-    default => sub { return XML::LibXML->new; },
-    lazy => 1,
-);
-has '_xslt_parser' => (
-    isa => "XML::LibXSLT",
-    is => 'rw',
-    default => sub { return XML::LibXSLT->new; },
-    lazy => 1,
-);
-has '_stylesheet' => (
-    isa => "XML::LibXSLT::StylesheetWrapper",
-    is => 'rw',
-    default => sub { return shift->_calc_stylesheet(), },
-    lazy => 1,
-);
+sub make_variant
+{
+    my ($class, $target_package, %args) = @_;
 
-sub _calc_stylesheet {
-    my $self = shift;
+    my $output_format = $args{output_format};
 
-    my $style_doc = $self->_xml_parser()->parse_file(
-        $self->dist_path_slot('xslt_transform_basename'),
+    with ('XML::GrammarBase::Role::XSLT::Global');
+
+    has "to_${output_format}_xslt_transform_basename"
+        => (isa => 'Str', is => 'rw');
+
+    has "_to_${output_format}_stylesheet" =>
+    (
+        isa => "XML::LibXSLT::StylesheetWrapper",
+        is => 'rw',
+        default => sub { return shift->_calc_stylesheet($output_format), },
+        lazy => 1,
     );
 
-    return $self->_xslt_parser->parse_stylesheet($style_doc);
-}
-
-sub _undefize
-{
-    my $v = shift;
-
-    return defined($v) ? $v : "(undef)";
-}
-
-sub _calc_and_ret_dom_without_validate
-{
-    my $self = shift;
-    my $args = shift;
-
-    my $source = $args->{source};
-
-    return
-          exists($source->{'dom'})
-        ? $source->{'dom'}
-        : exists($source->{'string_ref'})
-        ? $self->_xml_parser()->parse_string(${$source->{'string_ref'}})
-        : $self->_xml_parser()->parse_file($source->{'file'})
-        ;
-}
-
-sub _get_dom_from_source
-{
-    my $self = shift;
-    my $args = shift;
-
-    my $source_dom = $self->_calc_and_ret_dom_without_validate($args);
-
-    my $ret_code;
-
-    eval
-    {
-        $ret_code = $self->_rng()->validate($source_dom);
-    };
-
-    if (defined($ret_code) && ($ret_code == 0))
-    {
-        # It's OK.
-    }
-    else
-    {
-        confess "RelaxNG validation failed [\$ret_code == "
-            . _undefize($ret_code) . " ; $@]"
-            ;
-    }
-
-    return $source_dom;
-}
-
-sub perform_xslt_translation
-{
-    my ($self, $args) = @_;
-
-    my $source_dom = $self->_get_dom_from_source($args);
-
-    my $stylesheet = $self->_stylesheet();
-
-
-    my $medium = $args->{output};
-
-    my $is_string = ($medium eq 'string');
-    my $is_dom = ($medium eq 'dom');
-
-    if ($is_string or $is_dom)
-    {
-        my $results = $stylesheet->transform($source_dom);
-
-        return
-            $is_dom
-            ? $results
-            : $stylesheet->output_string($results)
-            ;
-    }
-    elsif (ref($medium) eq 'HASH')
-    {
-        if (exists($medium->{'file'}))
-        {
-            open my $out, '>', $medium->{'file'};
-            $self->perform_xslt_translation(
-                {
-                    %$args,
-                    output => {fh => $out,},
-                }
-            );
-            close ($out);
-            return;
-        }
-        if (exists($medium->{'fh'}))
-        {
-            print {$medium->{'fh'}}
-            $self->perform_xslt_translation(
-                {
-                    %$args,
-                    output => "string",
-                }
-            );
-            return;
-        }
-    }
-
-    confess "Unknown medium";
+    return;
 }
 
 =head1 SYNOPSIS
 
-    package XML::Grammar::MyGrammar::RelaxNG::Validate;
+    package XML::Grammar::MyGrammar::ToOtherStuff;
 
-    use Any::Moose;
+    use MooX 'late';
+
+    use XML::GrammarBase::Role::RelaxNG;
+    use XML::GrammarBase::Role::XSLT;
 
     with ('XML::GrammarBase::Role::RelaxNG');
+    with XSLT(output_format => 'html');
+    with XSLT(output_format => 'docbook');
 
-    has '+module_base' => (default => 'XML::Grammar::MyGrammar');
+    has '+module_base' => (default => 'XML-Grammar-MyGrammar');
     has '+rng_schema_basename' => (default => 'my-grammar.rng');
 
+    has '+to_html_xslt_transform_basename' => (default => 'mygrammar-xml-to-html.xslt');
+    has '+to_docbook_xslt_transform_basename' => (default => 'mygrammar-xml-to-docbook.xslt');
+
     package main;
 
-    my $rnger = XML::Grammar::MyGrammar::RelaxNG::Validate->new(
+    my $xslt = XML::Grammar::MyGrammar::ToOtherStuff->new(
         data_dir => "/path/to/data-dir",
     );
 
     # Throws an exception on failure.
-    $rnger->rng_validate_file("/different-path-to-xml-file.xml");
+    my $as_html = $xslt->perform_xslt_translation(
+        {
+            output_format => 'html'
+            source => {file => $input_filename, },
+            output => "string",
+        }
+    );
+
+=head1 PARAMATERS
+
+=head2 output_format
+
+A Perl identifier string identifying the format.
 
 =head1 SLOTS
 
 
 The Relax NG Schema basename.
 
+=head2 to_${output_format}_xslt_transform_basename
+
+The basename of the primary XSLT transform file. Should be overrided in
+the constructor or using C<has '+to_html'>. For example:
+
+    has '+to_html_xslt_transform_basename' => (default => 'fiction-xml-to-html.xslt');
+
 =head1 METHODS
 
 =head2 $self->rng_validate_dom($source_dom)
 
 =over 4
 
-=item * my $final_source = $converter->perform_xslt_translation({source => {file => $filename}, output => "string" })
+=item * my $final_source = $converter->perform_xslt_translation({output_format => $format, source => {file => $filename}, output => "string" })
 
-=item * my $final_source = $converter->perform_xslt_translation({source => {string_ref => \$buffer}, output => "string" })
+=item * my $final_source = $converter->perform_xslt_translation({output_format => $format, source => {string_ref => \$buffer}, output => "string" })
 
-=item * my $final_dom = $converter->perform_xslt_translation({source => {file => $filename}, output => "dom" })
+=item * my $final_dom = $converter->perform_xslt_translation({output_format => $format, source => {file => $filename}, output => "dom" })
 
-=item * my $final_dom = $converter->perform_xslt_translation({source => {dom => $libxml_dom}, output => "dom" })
+=item * my $final_dom = $converter->perform_xslt_translation({output_format => $format, source => {dom => $libxml_dom}, output => "dom" })
 
-=item * my $final_dom = $converter->perform_xslt_translation({source => {dom => $libxml_dom}, output => {file => $path_to_file,}, })
+=item * my $final_dom = $converter->perform_xslt_translation({output_format => $format, source => {dom => $libxml_dom}, output => {file => $path_to_file,}, })
 
-=item * my $final_dom = $converter->perform_xslt_translation({source => {dom => $libxml_dom}, output => {fh => $filehandle,}, })
+=item * my $final_dom = $converter->perform_xslt_translation({output_format => $format, source => {dom => $libxml_dom}, output => {fh => $filehandle,}, })
 
 =back
 
-Does the actual conversion. The C<'source'> argument points to a hash-ref with
+This method does the actual conversion with the output format of
+$format. The C<'source'> argument points to a hash-ref with
 keys and values for the source. If C<'file'> is specified there it points to the
 filename to translate (currently the only available source). If
 C<'string_ref'> is specified it points to a reference to a string, with the
 
 =head2 BUILD
 
-L<Any::Moose> constructor. For internal use.
+L<Moo> constructor. For internal use.
+
+=head2 make_variant
+
+L<Package::Variant> constructor. For internal use.
 
 =head1 AUTHOR
 
 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XML-GrammarBase>.  I will be notified, and then you'll
 automatically be notified of progress on your bug as I make changes.
 
+=head1 THANKS
 
-
+Thanks to Matt S. Trout L<http://metacpan.org/author/MSTROUT> and other
+people from #moose on irc.perl.org for helping me figure out
+L<Moo> / L<MooX> and steer me away from L<Any::Moose> , and for writing
+the L<Moo> ecosystem.
 
 =head1 SUPPORT
 

XML-GrammarBase/lib/XML/GrammarBase/Role/XSLT/Global.pm

+package XML::GrammarBase::Role::XSLT::Global;
+
+use strict;
+use warnings;
+
+
+=head1 NAME
+
+XML::GrammarBase::Role::XSLT - a parameterized role for an XSLT converter.
+
+=head1 VERSION
+
+Version 0.0.1
+
+=cut
+
+use Moo::Role;
+
+use MooX 'late';
+
+use XML::LibXML;
+use XML::LibXSLT;
+
+use autodie;
+
+our $VERSION = '0.0.1';
+
+with ('XML::GrammarBase::Role::RelaxNG');
+
+has '_xml_parser' => (
+    isa => "XML::LibXML",
+    is => 'rw',
+    default => sub { return XML::LibXML->new; },
+    lazy => 1,
+);
+
+has '_xslt_parser' => (
+    isa => "XML::LibXSLT",
+    is => 'rw',
+    default => sub { return XML::LibXSLT->new; },
+    lazy => 1,
+);
+
+sub _calc_stylesheet {
+    my ($self, $output_format) = @_;
+
+    my $style_doc = $self->_xml_parser()->parse_file(
+        $self->dist_path_slot("to_${output_format}_xslt_transform_basename"),
+    );
+
+    return $self->_xslt_parser->parse_stylesheet($style_doc);
+}
+
+sub _calc_and_ret_dom_without_validate
+{
+    my $self = shift;
+    my $args = shift;
+
+    my $source = $args->{source};
+
+    return
+          exists($source->{'dom'})
+        ? $source->{'dom'}
+        : exists($source->{'string_ref'})
+        ? $self->_xml_parser()->parse_string(${$source->{'string_ref'}})
+        : $self->_xml_parser()->parse_file($source->{'file'})
+        ;
+}
+
+sub _get_dom_from_source
+{
+    my $self = shift;
+    my $args = shift;
+
+    my $source_dom = $self->_calc_and_ret_dom_without_validate($args);
+
+    my $ret_code;
+
+    eval
+    {
+        $ret_code = $self->_rng()->validate($source_dom);
+    };
+
+    if (defined($ret_code) && ($ret_code == 0))
+    {
+        # It's OK.
+    }
+    else
+    {
+        confess "RelaxNG validation failed [\$ret_code == "
+            . $self->_undefize($ret_code) . " ; $@]"
+            ;
+    }
+
+    return $source_dom;
+}
+
+sub perform_xslt_translation
+{
+    my ($self, $args) = @_;
+
+    my $output_format = $args->{output_format};
+    my $source_dom = $self->_get_dom_from_source($args);
+
+    my $stylesheet_method = "_to_${output_format}_stylesheet";
+    my $stylesheet = $self->$stylesheet_method();
+
+
+    my $medium = $args->{output};
+
+    my $is_string = ($medium eq 'string');
+    my $is_dom = ($medium eq 'dom');
+
+    if ($is_string or $is_dom)
+    {
+        my $results = $stylesheet->transform($source_dom);
+
+        return
+            $is_dom
+            ? $results
+            : $stylesheet->output_string($results)
+            ;
+    }
+    elsif (ref($medium) eq 'HASH')
+    {
+        if (exists($medium->{'file'}))
+        {
+            open my $out, '>', $medium->{'file'};
+            $self->perform_xslt_translation(
+                {
+                    %$args,
+                    output => {fh => $out,},
+                }
+            );
+            close ($out);
+            return;
+        }
+        if (exists($medium->{'fh'}))
+        {
+            print {$medium->{'fh'}}
+            $self->perform_xslt_translation(
+                {
+                    %$args,
+                    output => "string",
+                }
+            );
+            return;
+        }
+    }
+
+    confess "Unknown medium";
+}
+
+=head1 SYNOPSIS
+
+    package XML::Grammar::MyGrammar::RelaxNG::Validate;
+
+    use Moo;
+
+    with ('XML::GrammarBase::Role::XSLT::Global');
+
+=head1 DESCRIPTION
+
+This is a utility global (non-variant) role used by
+L<XML::GrammarBase::Role::XSLT> . For internal use.
+
+=head1 METHODS
+
+=head2 $self->perform_xslt_translation(...)
+
+See L<XML::GrammarBase::Role::XSLT> .
+
+=head1 AUTHOR
+
+Shlomi Fish, C<< <shlomif at cpan.org> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to C<bug-xml-grammarbase at rt.cpan.org>, or through
+the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XML-GrammarBase>.  I will be notified, and then you'll
+automatically be notified of progress on your bug as I make changes.
+
+
+
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+    perldoc XML::GrammarBase
+
+You can also look for information at:
+
+=over 4
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=XML-GrammarBase>
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/XML-GrammarBase>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/XML-GrammarBase>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/XML-GrammarBase/>
+
+=back
+
+
+=head1 ACKNOWLEDGEMENTS
+
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009 Shlomi Fish.
+
+This program is distributed under the MIT (X11) License:
+L<http://www.opensource.org/licenses/mit-license.php>
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+=cut
+
+1; # End of XML::GrammarBase::RelaxNG::Validate
+

XML-GrammarBase/t/data/fiction-xml-test-docbook-xslt-output.docbook.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<article xmlns="http://docbook.org/ns/docbook" xmlns:fic="http://web-cpan.berlios.de/modules/XML-Grammar-Fortune/fiction-xml-0.2/" xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="index" xml:lang="" version="5.0">
+  <db:info>
+    <db:title>David vs. Goliath - Part I</db:title>
+  </db:info>
+  <section xml:id="top">
+    <db:info>
+      <db:title>The Top Section</db:title>
+    </db:info>
+    <db:para>
+    King <db:link xlink:href="http://en.wikipedia.org/wiki/David">David</db:link> and Goliath were standing by each other.
+    </db:para>
+    <db:para>
+    David said unto Goliath: "I will shoot you. I <db:emphasis role="bold">swear</db:emphasis> I will"
+    </db:para>
+    <section xml:id="goliath">
+      <db:info>
+        <db:title>Goliath's Response</db:title>
+      </db:info>
+      <db:para>
+    Goliath was not amused.
+    </db:para>
+      <db:para>
+    He said to David: "Oh, really. <db:emphasis>David</db:emphasis>, the red-headed!".
+    </db:para>
+      <db:para>
+    David started listing Goliath's disadvantages:
+    </db:para>
+      <db:blockquote xml:lang="fr-FR" xml:id="my_blockquote">
+    <db:orderedlist>
+    <db:listitem>
+    <db:para>
+    You're slow.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    You're big.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    You're stupid.
+    </db:para>
+    </db:listitem>
+    </db:orderedlist>
+    <db:para>
+    Goliath was insulted and told David he should use bullets for the
+    points, instead:
+    </db:para>
+    <db:itemizedlist>
+    <db:listitem>
+    <db:para>
+    David.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    Saul.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    Jonathan.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    Michal.
+    </db:para>
+    </db:listitem>
+    <db:listitem>
+    <db:para>
+    Meyrav.
+    </db:para>
+    </db:listitem>
+    </db:itemizedlist>
+    </db:blockquote>
+    </section>
+  </section>
+</article>

XML-GrammarBase/t/data/fiction-xml-to-docbook.xslt

+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version = '1.0'
+    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+    xmlns:fic="http://web-cpan.berlios.de/modules/XML-Grammar-Fortune/fiction-xml-0.2/"
+    xmlns="http://docbook.org/ns/docbook"
+    xmlns:db="http://docbook.org/ns/docbook"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<xsl:output method="xml" encoding="UTF-8" indent="yes"
+ />
+
+<xsl:template match="/">
+        <xsl:apply-templates select="//fic:body" />
+</xsl:template>
+
+<xsl:template match="fic:body">
+    <article>
+        <xsl:attribute name="xml:id">
+            <xsl:value-of select="@xml:id" />
+        </xsl:attribute>
+        <xsl:attribute name="xml:lang">
+            <xsl:value-of select="@xml:lang" />
+        </xsl:attribute>
+        <xsl:attribute name="version">5.0</xsl:attribute>
+        <db:info>
+            <db:title>
+                <xsl:value-of select="fic:title" />
+            </db:title>
+        </db:info>
+        <xsl:apply-templates select="fic:section" />
+    </article>
+</xsl:template>
+
+<xsl:template match="fic:section">
+    <section>
+        <xsl:copy-of select="@xml:id" />
+        <xsl:if test="@xml:lang">
+            <xsl:copy-of select="@xml:lang" />
+        </xsl:if>
+        <!-- Make the title the title attribute or "ID" if does not exist. -->
+        <db:info>
+            <db:title>
+                <xsl:choose>
+                    <xsl:when test="fic:title">
+                        <xsl:value-of select="fic:title" />
+                    </xsl:when>
+                    <xsl:otherwise>
+                        <xsl:value-of select="@xml:id" />
+                    </xsl:otherwise>
+                </xsl:choose>
+            </db:title>
+        </db:info>
+        <xsl:apply-templates select="fic:section|fic:blockquote|fic:p|fic:ol|fic:ul|fic:programlisting" />
+    </section>
+</xsl:template>
+
+<xsl:template match="fic:p">
+    <db:para>
+        <xsl:apply-templates />
+    </db:para>
+</xsl:template>
+
+<xsl:template match="fic:b">
+    <db:emphasis role="bold">
+        <xsl:apply-templates/>
+    </db:emphasis>
+</xsl:template>
+
+<xsl:template name="common_attributes">
+    <xsl:if test="@xlink:href">
+        <xsl:copy-of select="@xlink:href" />
+    </xsl:if>
+    <xsl:if test="@xml:lang">
+        <xsl:copy-of select="@xml:lang" />
+    </xsl:if>
+    <xsl:if test="@xml:id">
+        <xsl:copy-of select="@xml:id" />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="fic:blockquote">
+    <db:blockquote>
+        <xsl:call-template name="common_attributes" />
+        <xsl:apply-templates/>
+    </db:blockquote>
+</xsl:template>
+
+<xsl:template match="fic:i">
+    <db:emphasis>
+        <xsl:apply-templates/>
+    </db:emphasis>
+</xsl:template>
+
+<xsl:template match="fic:ol">
+    <db:orderedlist>
+        <xsl:apply-templates/>
+    </db:orderedlist>
+</xsl:template>
+
+<xsl:template match="fic:ul">
+    <db:itemizedlist>
+        <xsl:apply-templates/>
+    </db:itemizedlist>
+</xsl:template>
+
+<xsl:template match="fic:programlisting">
+    <db:programlisting>
+        <xsl:apply-templates/>
+    </db:programlisting>
+</xsl:template>
+
+<xsl:template match="fic:li">
+    <db:listitem>
+        <xsl:apply-templates/>
+    </db:listitem>
+</xsl:template>
+
+<xsl:template match="fic:span">
+    <xsl:variable name="tag_name">
+        <xsl:choose>
+            <xsl:when test="@xlink:href">
+                <xsl:value-of select="'db:link'" />
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:value-of select="'db:phrase'" />
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:variable>
+    <xsl:element name="{$tag_name}">
+        <xsl:call-template name="common_attributes" />
+        <xsl:apply-templates/>
+    </xsl:element>
+</xsl:template>
+
+</xsl:stylesheet>

XML-GrammarBase/t/multi-xslt.t

+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 10;
+
+package MyGrammar::MultiXSLT;
+
+use MooX 'late';
+
+use File::Spec;
+
+use XML::GrammarBase::Role::RelaxNG;
+use XML::GrammarBase::Role::XSLT;
+
+with ('XML::GrammarBase::Role::RelaxNG');
+with XSLT(output_format => 'html');
+with XSLT(output_format => 'docbook');
+
+has '+module_base' => (default => 'XML-GrammarBase');
+has '+data_dir' => (default => File::Spec->catdir(File::Spec->curdir(), "t", "data"));
+has '+rng_schema_basename' => (default => 'fiction-xml.rng');
+
+has '+to_html_xslt_transform_basename' => (default => 'fiction-xml-to-html.xslt');
+has '+to_docbook_xslt_transform_basename' => (default => 'fiction-xml-to-docbook.xslt');
+
+package main;
+
+use Test::XML::Ordered qw(is_xml_ordered);
+
+use File::Temp qw(tempfile);
+
+my @is_xml_common = (validation => 0, load_ext_dtd => 0, no_network => 1);
+
+sub my_is_xml
+{
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+    my ($got, $expected, $blurb) = @_;
+
+    return is_xml_ordered(
+        [ @{$got}, @is_xml_common, ],
+        [ @{$expected}, @is_xml_common, ],
+        {},
+        $blurb,
+    );
+}
+
+sub _utf8_slurp
+{
+    my $filename = shift;
+
+    open my $in, '<', $filename
+        or die "Cannot open '$filename' for slurping - $!";
+
+    binmode $in, ':encoding(utf8)';
+
+    local $/;
+    my $contents = <$in>;
+
+    close($in);
+
+    return $contents;
+}
+
+# TEST:$c=0;
+sub test_file
+{
+    my $args = shift;
+
+    my $input_fn = $args->{input_fn};
+    my $output_fn = $args->{output_fn};
+    my $output_format = $args->{output_format};
+
+    my $xslt = MyGrammar::MultiXSLT->new();
+
+    {
+        my $final_source = $xslt->perform_xslt_translation(
+            {
+                output_format => $output_format,
+                source => {file => $input_fn, },
+                output => "string",
+            }
+        );
+
+        my $xml_source = _utf8_slurp($output_fn);
+
+        # TEST:$c++;
+        my_is_xml(
+            [ string => $final_source, ],
+            [ string => $xml_source, ],
+            "'$input_fn' generated good output on source/input_filename - output - string"
+        );
+    }
+
+    {
+        my $final_source = $xslt->perform_xslt_translation(
+            {
+                output_format => $output_format,
+                source => {string_ref => \(_utf8_slurp($input_fn)) },
+                output => "string",
+            }
+        );
+
+        my $xml_source = _utf8_slurp($output_fn);
+
+        # TEST:$c++;
+        my_is_xml(
+            [ string => $final_source, ],
+            [ string => $xml_source, ],
+            "'$input_fn' generated good output on source/string_ref - output - string"
+        );
+    }
+
+    {
+        my $final_dom = $xslt->perform_xslt_translation(
+            {
+                output_format => $output_format,
+                source => {string_ref => \(_utf8_slurp($input_fn)) },
+                output => "dom",
+            }
+        );
+
+        my $xml_source = _utf8_slurp($output_fn);
+
+        # TEST:$c++;
+        my_is_xml(
+            [ string => $final_dom->toString(), ],
+            [ string => $xml_source, ],
+            "'$input_fn' generated good output on source/string_ref - output - dom"
+        );
+    }
+
+    {
+        my ($fh, $filename) = tempfile();
+
+        $xslt->perform_xslt_translation(
+            {
+                output_format => $output_format,
+                source => {string_ref => \(_utf8_slurp($input_fn)) },
+                output => {file => $filename, },
+            }
+        );
+
+        my $xml_source = _utf8_slurp($output_fn);
+        my $final_source = _utf8_slurp($filename);
+
+        # TEST:$c++;
+        my_is_xml(
+            [ string => $final_source, ],
+            [ string => $xml_source, ],
+            "'$input_fn' generated good output on source/string_ref - output/file"
+        );
+    }
+
+    {
+        my ($fh, $filename) = tempfile();
+
+        $xslt->perform_xslt_translation(
+            {
+                output_format => $output_format,
+                source => {string_ref => \(_utf8_slurp($input_fn)) },
+                output => {fh => $fh, },
+            }
+        );
+
+        close($fh);
+
+        my $xml_source = _utf8_slurp($output_fn);
+        my $final_source = _utf8_slurp($filename);
+
+        # TEST:$c++;
+        my_is_xml(
+            [ string => $final_source, ],
+            [ string => $xml_source, ],
+            "'$input_fn' generated good output on source/string_ref - output/fh"
+        );
+    }
+    return;
+}
+
+# TEST:$test_file=$c;
+
+# TEST*$test_file
+test_file(
+    {
+        output_format => 'html',
+        input_fn => File::Spec->catfile(
+            File::Spec->curdir(), "t", "data", "fiction-xml-test.xml",
+        ),
+        output_fn => File::Spec->catfile(
+            File::Spec->curdir(), "t", "data", "fiction-xml-test-html-xslt-output.xhtml",
+        ),
+    }
+);
+
+# TEST*$test_file
+test_file(
+    {
+        output_format => 'docbook',
+        input_fn => File::Spec->catfile(
+            File::Spec->curdir(), "t", "data", "fiction-xml-test.xml",
+        ),
+        output_fn => File::Spec->catfile(
+            File::Spec->curdir(), "t", "data", "fiction-xml-test-docbook-xslt-output.docbook.xml",
+        ),
+    }
+);

XML-GrammarBase/t/xslt.t

 
 use File::Spec;
 
-with ('XML::GrammarBase::Role::XSLT');
+use XML::GrammarBase::Role::RelaxNG;
+use XML::GrammarBase::Role::XSLT;
+
+with ('XML::GrammarBase::Role::RelaxNG');
+with XSLT(output_format => 'html');
 
 has '+module_base' => (default => 'XML-GrammarBase');
 has '+data_dir' => (default => File::Spec->catdir(File::Spec->curdir(), "t", "data"));
-has '+xslt_transform_basename' => (default => 'fiction-xml-to-html.xslt');
 has '+rng_schema_basename' => (default => 'fiction-xml.rng');
 
+has '+to_html_xslt_transform_basename' => (default => 'fiction-xml-to-html.xslt');
+
 package main;
 
 use Test::XML::Ordered qw(is_xml_ordered);
     {
         my $final_source = $xslt->perform_xslt_translation(
             {
+                output_format => 'html',
                 source => {file => $input_fn, },
                 output => "string",
             }
     {
         my $final_source = $xslt->perform_xslt_translation(
             {
+                output_format => 'html',
                 source => {string_ref => \(_utf8_slurp($input_fn)) },
                 output => "string",
             }
     {
         my $final_dom = $xslt->perform_xslt_translation(
             {
+                output_format => 'html',
                 source => {string_ref => \(_utf8_slurp($input_fn)) },
                 output => "dom",
             }
 
         $xslt->perform_xslt_translation(
             {
+                output_format => 'html',
                 source => {string_ref => \(_utf8_slurp($input_fn)) },
                 output => {file => $filename, },
             }
 
         $xslt->perform_xslt_translation(
             {
+                output_format => 'html',
                 source => {string_ref => \(_utf8_slurp($input_fn)) },
                 output => {fh => $fh, },
             }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.