CSCI 5733
XML Application Development
Spring 2006
Suggested Solution to Homework #1
(a) For example (not fully documented):
# h1a.pl
#
use strict;
open DATA, "<$ARGV[0]" || die "Can't open input file $ARGV[0].\n";
print <<_HEADER;
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<name>Address List</name>
<Folder>
<name>Locations</name>
<open>1</open>
_HEADER
# Discard first line.
$_ = <DATA>;
while ($_ = <DATA>) {
chomp;
my @field = split /\t/;
my $description = "http://$field[13]";
$field[5] =~ s/^(\d{5}).*$/\1/;
my $address = "$field[2], $field[3], $field[4] $field[5]";
my $name = $field[1];
$description = xmlencode($description);
$address = xmlencode($address);
$name = xmlencode($name);
print <<_FIELD;
<Placemark>
<description>$description</description>
<address>$address</address>
<name>$name</name>
</Placemark>
_FIELD
}
print <<_FOOTER;
</Folder>
</Document>
</kml>
_FOOTER
exit 0;
sub xmlencode {
my $s = shift;
$s =~ s/&/&/g;
$s =~ s/</</g;
$s =~ s/>/>/g;
$s =~ s/'/'/g;
$s =~ s/"/"/g;
$s;
}
Dr. Kwok-Bun Yue
Professor, Computer Science and Computer Information Systems
Chair, Division of Computing and Mathematics
University of Houston-Clear Lake
2700 Bay Area Boulevard
Houston, TX 77058
Yue's home page
yue@uhcl.edu
281-283-3864
#
# h1b.pl Extracting data from an XML file and store it in a MySQL database.
# See specification of HW #1 Question (b) of CSCI 5733, Spring 2006
#
# By Kwok-Bun Yue, 1/14/2006
#
use strict;
use DBI;
open DATA, "<$ARGV[0]" || die "Can't open $ARGV[0]";
my @lines = <DATA>;
chomp @lines;
my $line = join "", @lines;
# Create tables: assume not already exist.
my $dbh = DBI->connect( 'dbi:mysql:whatever',
'user',
'pass'
) || die "Database connection not made: $DBI::errstr";
my $sth = $dbh->prepare("CREATE TABLE articles (
aid INT,
volume INT,
number INT,
title VARCHAR(200),
initPage INT,
endPage INT,
KEY (aid));");
$sth->execute();
$sth = $dbh->prepare("CREATE TABLE authors (
author VARCHAR(50),
aid INT,
position CHAR(2),
KEY (author, aid),
CONSTRAINT FOREIGN KEY (aid) REFERENCES articles(aid));");
$sth->execute();
my $artNum = 0;
while ($line =~/<issue>(.*?)<\/issue>/gsi) {
my $issue = $1;
my ($volume, $number) = $issue =~ /<volume>(.*?)<\/volume>.*?<number>(.*)<\/number>/;
while ($issue =~ /<article>(.*?)<\/article>/gsi) {
$artNum++;
my $article = $1;
my ($title) = $article =~ /<title>(.*?)<\/title>/;
my ($initPage) = $article =~ /<initPage>(.*?)<\/initPage>/;
my ($endPage) = $article =~ /<endPage>(.*?)<\/endPage>/;
$article = xmlDecode($article);
$dbh->do("INSERT INTO articles(aid, volume, number, title, initPage, endPage) VALUES(?,?,?,?,?,?)",
{}, $artNum, $volume, $number, $title, $initPage, $endPage);
while ($article =~ /<author\s+position="(.*?)">(.*?)<\/author>/gsi) {
my ($position, $author) = ($1, $2);
$author = xmlDecode($author);
$position = xmlDecode($position);
$dbh->do("INSERT INTO authors(author, aid, position) VALUES(?,?,?)",
{}, $author, $artNum, $position) || print "error: ", $DBI::errstr , "\n";
}
}
}
$dbh->disconnect();
exit 0;
sub xmlDecode {
my $s = shift;
$s =~ s/</</g;
$s =~ s/>/>/g;
$s =~ s/"/"/g;
$s =~ s/'/'/g;
$s =~ s/&/&/g;
$s;
}
(c) For example:
use CGI;
use DBI;
use strict;
$|++;
#
# h1c.pl
#
# By Kwok-Bun Yue January 13, 2006
#
# A simple CGI-Perl program to serve as a simple XML server.
# See http://localhost/yue/courses/xml/spring2006/hw/h1.asp
#
# Source Input:
# MySQL Database
#
# HTTP parameters:
# authors=yes: returns a list of all authors in XML.
# author=<author>: returns the articles published by the author in XML.
# issues: returns a list of all issues (volume and number) in XML.
# volume=<volume>&number=<number>,: returns all article titles in the given issue in XML.
# Porting variables:
# My SQL credential.
my $user = '';
my $pass = '';
# Variables.
my $dbh; # database handle
my $q = new CGI;
# HTTP parameters
my $authors = $q->param("authors");
my $author = $q->param("author");
my $issues = $q->param("issues");
my $volume = $q->param("volume");
my $number = $q->param("number");
if ($authors) {
&returnAuthors();
exit 0;
}
if ($author) {
&returnAuthor($author);
exit 0;
}
if ($issues) {
&returnIssues();
exit 0;
}
if ($volume || $number) {
&returnIssue($volume, $number);
exit 0;
}
print <<_EMPTY_XML;
Content-Type: text/xml; charset=ISO-8859-1
<?xml version='1.0' encoding='ISO-8859-1' ?>
<noResult />
_EMPTY_XML
exit 0; # main
sub returnAuthors {
print <<_HEAD;
Content-Type: text/xml; charset=ISO-8859-1
<?xml version='1.0' encoding='ISO-8859-1' ?>
<authors>
_HEAD
my $dbh = DBI->connect("DBI:mysql:database=database;host=localhost;port=3306", $user, $pass)
|| die "Can't connect to the database";
my @row;
my $sth=$dbh->prepare("SELECT DISTINCT author FROM authors");
$sth->execute();
while(@row=$sth->fetchrow_array()){
my $author = xmlEncode(${row[0]});
print " <author>$author</author>\n";
}
print "</authors>";
$sth->finish();
} # returnAuthors
sub returnAuthor {
my $author = shift;
print <<_HEAD;
Content-Type: text/xml; charset=ISO-8859-1
<?xml version='1.0' encoding='ISO-8859-1' ?>
<articles author="$author">
_HEAD
my $dbh = DBI->connect("DBI:mysql:database=database;host=localhost;port=3306", $user, $pass)
|| die "Can't connect to the database";
my @row;
my $authorStr = $author;
$authorStr =~ s/'/''/g;
my $sth=$dbh->prepare("SELECT DISTINCT title, volume, number FROM articles, authors where articles.aid = authors.aid and authors.author = '$authorStr'");
$sth->execute();
while(@row=$sth->fetchrow_array()){
my $author = xmlEncode(${row[0]});
print " <article volume=\"${row[1]}\" number=\"${row[2]}\">$author</article>\n";
}
print "</articles>";
$sth->finish();
} # returnAuthor
sub returnIssues {
print <<_HEAD;
Content-Type: text/xml; charset=ISO-8859-1
<?xml version='1.0' encoding='ISO-8859-1' ?>
<issues>
_HEAD
my $dbh = DBI->connect("DBI:mysql:database=database;host=localhost;port=3306", $user, $pass)
|| die "Can't connect to the database";
my @row;
my $sth=$dbh->prepare("SELECT DISTINCT volume, number FROM articles");
$sth->execute();
while(@row=$sth->fetchrow_array()){
print " <issue volume=\"${row[0]}\" number=\"${row[1]}\" />\n";
}
print "</issues>";
$sth->finish();
} # returnIssues
sub returnIssue {
my ($volume, $number) = @_;
print <<_HEAD;
Content-Type: text/xml; charset=ISO-8859-1
<?xml version='1.0' encoding='ISO-8859-1' ?>
<issue volume="$volume" number="$number">
_HEAD
my $dbh = DBI->connect("DBI:mysql:database=database;host=localhost;port=3306", $user, $pass)
|| die "Can't connect to the database";
my @row;
$volume = xmlencode($volume);
$number = xmlencode($number);
my $sth=$dbh->prepare("SELECT DISTINCT title FROM articles where volume = '$volume' and number = '$number'");
$sth->execute();
while(@row=$sth->fetchrow_array()){
my $title = xmlEncode($row[0]);
print " <article>$title</article>\n";
}
print "</issue>";
$sth->finish();
} # returnAuthor
sub xmlEncode {
my $s = shift;
$s =~ s/&/&/g;
$s =~ s/</</g;
$s =~ s/>/>/g;
$s =~ s/'/'/g;
$s =~ s/"/"/g;
$s;
}
sub xmlDecode {
my $s = shift;
$s =~ s/</</g;
$s =~ s/>/>/g;
$s =~ s/"/"/g;
$s =~ s/'/'/g;
$s =~ s/&/&/g;
$s;
}