Problem : I have a XML snippet stored in a DB which I want to combine with several other fields from the DB and present them using HTML from PHP.
My Solution: I have Perl Backend script which does
$query = "select id, description, xml_content, name from table where id = '$id'";
then modifies the XML to include these field.
$xml_content =~ s|<Record>|<Record name="$name" id="$id" desc="$desc">|i;
I then use XSL file to transform this to
<xsl:output method="html"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<form action="info.php" method="get" accept-charset="utf-8">
<label for="id">Display xml for: </label>
<input type="text" name="id" value="" id="id" size="40"/>
<p><input type="submit" value="Display it! →"/></p>
</form>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="doc:Record">
<p>
<xsl:choose>
<xsl:when test="./@none">
XML Content ID <xsl:value-of select="@id"/> NOT FOUND
</xsl:when>
<xsl:otherwise>
XML Content ID <xsl:value-of select="@id"/> Found
<xsl:value-of select="@desc"/> - <xsl:value-of select="@name"/>
</xsl:otherwise>
</xsl:choose>
</p>
</xsl:template>
I then use PHP to get the CGI vars and run the perl script and display the output.
<?php
if (!empty($_GET['id'])) {
$command = "getxml.pl --id=" . $_GET['id'];
$process = proc_open($command, $descriptorspec, $pipes, null, $_SERVER);
if (is_resource($process)) {
$line = stream_get_contents($pipes[1]);
} else {
$line = '<Record none="" desc="' . $command . '"></Record>';
}
}
header('Content-type: text/xml');
echo '<?xml version="1.0" encoding="ISO-8859-1"?>';
echo '<?xml-stylesheet type="text/xsl" href="xmlinfo.xsl"?>';
echo "\n";
if (empty($command)) {
#Display the form only.
$line = '<Record></Record >';
}
echo "$line \n";
?>
Since PHP was configured without xslt, this is the only I could think of to display the XML in HTML using PHP.
My question is:
<html><body><form>
part in XSL and put it into PHP. It would seem much cleaner that way. Thanks.
Here is an example using an actual framework. The framework I use is Mojolicious for Perl, certainly others could also handle this. I setup several database handling methods (which you might be able to adapt from your original script). Then I use the built-in XML parser to update the record's attribute.
Finally I setup two routes. When run if you visit /
you get your page as requested. Note that the XML has been escaped (in the template) so that it renders as text to the browser. This can be changed if you prefer some other form of display. If you visit /record?id=1
you get the XML result directly. This is more useful for a RESTful interface.
Lets say you name it app.pl
. To run it you can simply
./app.pl daemon
then visit http://localhost:3000
to view using one of mojo's built-in servers (yes it does run under CGI too).
Or you can actually interact with the script. Say you want to just see one record at the command line
./app.pl get '/record?id=1'
or perhaps you want to insert something, the helper
s are available via eval
./app.pl eval 'app->insert(2, "Something", "<Record>Something Else</Record>", "Name")'
Cool eh?
#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojo::DOM;
use DBI;
# connect to database
use DBI;
helper db => sub {
state $dbh = DBI->connect("dbi:SQLite:database.db","","") or die "Could not connect";
};
# add helper methods for interacting with database
helper create_table => sub {
my $self = shift;
warn "Creating table 'records'\n";
$self->db->do('CREATE TABLE records (id INT, description TEXT, xml_content TEXT, name VARCHAR(255));');
$self->insert(1,'Description','<Record>Contents</Record>','Name');
};
helper select => sub {
my $self = shift;
my $sth = eval { $self->db->prepare('SELECT * FROM records WHERE id = ?') } || return undef;
my $id = shift or return 0;
$sth->execute($id);
return $sth->fetchrow_hashref;
};
helper insert => sub {
my $self = shift;
my ($id, $description, $xml, $name) = @_;
my $sth = eval { $self->db->prepare('INSERT INTO records VALUES (?,?,?,?)') } || return undef;
$sth->execute($id, $description, $xml, $name);
return 1;
};
# if statement didn't prepare, assume its because the table doesn't exist
defined app->select or app->create_table;
helper 'xml_by_id' => sub {
my $self = shift;
my $id = shift;
my $row = $self->select($id) || {};
return '<Record></Record>' unless keys %$row;
my $xml = Mojo::DOM->new->xml(1)->parse( $row->{xml_content} );
my $record = $xml->at('Record');
for my $key ( qw/ name id description / ) {
$record->{$key} = $row->{$key};
}
return wantarray ? ($xml, $row) : $xml;
};
any '/record' => sub {
my $self = shift;
my $id = $self->param('id') || $self->render_not_found;
my $xml = $self->xml_by_id($id);
$self->render( text => $xml, format => 'xml' );
};
any '/' => sub {
my $self = shift;
if ( my $id = $self->param('id') ) {
my ($xml, $row) = $self->xml_by_id($id);
$self->stash( id => $id );
$self->stash( xml => $xml );
$self->stash( row => $row );
}
$self->render('index');
};
app->start;
__DATA__
@@ index.html.ep
<!DOCTYPE html>
<html>
<head><title>Get XML</title></head>
<body>
<form action="/" method="get" accept-charset="utf-8">
<label for="id">Display xml for: </label>
<input type="text" name="id" value="" id="id" size="40"/>
<p><input type="submit" value="Display it! →"/></p>
</form>
% if ( my $id = stash('id') ) {
<p> XML Content ID <%= $id %>
% my $row = stash('row');
% if ( keys %$row ) {
Found
<%= $row->{description} %> - <%= $row->{name} %>
%} else {
NOT FOUND
%}
</p>
%= stash('xml')
% }
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With