The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# -*- perl -*-

#
# $Id: XML.pm,v 1.7 2004/03/21 23:11:32 eserte Exp $
# Author: Slaven Rezic
#
# Copyright (C) 2003 Slaven Rezic.
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License, see the file COPYING.

#
# Mail: slaven@rezic.de
# WWW:  http://we-framework.sourceforge.net
#

package WE_Content::XML;
use base qw(WE_Content::Base);

use strict;
use vars qw($VERSION);
$VERSION = sprintf("%d.%02d", q$Revision: 1.7 $ =~ /(\d+)\.(\d+)/);

use XML::Dumper 0.71 (); # earlier versions were not reliable

sub new {
    my($class, %args) = @_;
    my $self = {};
    while(my($k,$v) = each %args) {
	die "Option does not start with a dash: $k" if $k !~ /^-/;
	$self->{ucfirst(substr($k,1))} = $v;
    }
    bless $self, $class;
    if ($self->{File}) {
	$self->parse(-file => $self->{File});
    } elsif ($self->{String}) {
	$self->parse(-string => $self->{String});
    }
    $self->_create_parser;
    $self;
}

sub _create_parser {
    my $self = shift;
    $self->{P} = XML::Dumper->new;
}

sub parse {
    my($self, %args) = @_;
    my $buf = $self->get_string(%args);

    my $emptydata;
    if (!$self->{P}) { $self->_create_parser }
    my $outdata = eval { local $SIG{__DIE__}; $self->{P}->xml2pl($buf) };
    if ($@) {
	my $line = 1;
	warn join("\n", map { sprintf("%3d: %s", $line++, $_) } split /\n/, $buf);
	die $@;
    }
    if (!defined $outdata) {
	die "Loading emptydata not yet supported...";
    }

    if (defined $outdata) {
	$self->{Object} = $outdata;
	$self->{Type}   = 'content';
    } elsif (defined $emptydata) {
	$self->{Object} = eval $emptydata; # XXX should use Safe!
	$self->{Type}   = 'template';
    } else {
	die "No data found!";
    }

    $self->{Object};
}

sub serialize {
    my $self = shift;
    if (!$self->{P}) { $self->_create_parser() }
    my $xml = '<?xml version="1.0" encoding="utf-8"?>' . $self->{P}->pl2xml($self->{Object});
    if      ($self->_can_XML_LibXSLT) {
	$xml = $self->_beautify_with_XML_LibXSLT($xml);
    } elsif ($self->_can_XML_XSLT) {
	$xml = $self->_beautify_with_XML_XSLT($xml);
    }
    $xml;
}

sub ext { "xml" }

sub _can_XML_XSLT {
    my $self = shift;
    warn "Can't use the identity idiom with XML::XSLT (yet)";
    return 0;
    eval { require XML::XSLT; 1 };
}

sub _beautify_with_XML_XSLT {
    my($self, $xml) = @_;
    my $xslt = XML::XSLT->new($self->stylesheet);
    $xslt->transform($xml);
    $xml = $xslt->toString;
    $xslt->dispose;
    $xml;
}

sub _can_XML_LibXSLT {
    my $self = shift;
    eval {
	require XML::LibXML;
	require XML::LibXSLT;
	1;
    };
}

sub _beautify_with_XML_LibXSLT {
    my($self, $xml) = @_;

    my $parser = XML::LibXML->new();
    my $xslt = XML::LibXSLT->new();

    my $source = $parser->parse_string($xml);
    my $style_doc = $parser->parse_string($self->stylesheet);

    my $stylesheet = $xslt->parse_stylesheet($style_doc);

    my $results = $stylesheet->transform($source);

    $stylesheet->output_string($results);
}

sub stylesheet {
    <<'EOF';
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:template match="@memory_address" />
 <xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
EOF
}

1;

__END__

=head1 NAME

WE_Content::XML - web.editor content in XML files

=head1 SYNOPSIS


=head1 DESCRIPTION

=head1 HISTORY

Versions until 1.03 used to use L<XML::Simple>. Now the module uses
L<XML::Dumper>, because XML::Simple is not able to reliable serialize
and deserialize data, as stated by the XML::Simple author.

=head1 AUTHOR

Slaven Rezic - slaven@rezic.de

=head1 SEE ALSO

L<WE_Content::Base>, L<XML::Dumper>.

=cut