|
|
Examples
Here we present several examples of XCentric programs. Some of these
examples are from the XQuery
use
cases proposed by W3C.
Also note that the distribution of XCentric includes these and several
other examples.
Example 1. Given this
XML file with a set of publications, detect which have a publisher tag
and which don't and for those having a publisher tag, print its content:
verpub(URL):-
http2pro(URL,Pubs),
Pubs =*=
pubs([],_,pub([],_,title([],NP),Rem),_),
write(NP),write('
'),decide(Rem),nl.
decide(<_,publisher([],Pub),_>):-
write('has
publisher: '),write(Pub),!.
decide(_):-
write('does not have
publisher.').
We start by extracting the sequence of elements possible
including the publisher tag and output a list of publications
indicating the publisher name when it is available. The result follows:
Type-based XML Processing in
Logic Programming has publisher: Springer
Verlag
Linearization of the Lambda-Calculus and its Relation with Intersection
Type Systems does not have publisher.
On Avoiding Redundancy in Inductive Logic Programming has
publisher:
Springer Verlag
Mob: A Scripting Language for Mobile Agents based on a Process
Calculus has publisher: Springer
Verlag
Example 2. In this example we have
one Xml document for an address book (addressbook.xml).
This document has records with optional email tags. Here we want to
create a new document containing only the records with one or more
email tags. We define the type of the record and process the document
has described (note that the <X1,...Xn> unifies with a
sequence of n elements):
:-use_module([xcentric,xml2prolog,prolog2xml]).
:- type tr --->
record([],name([],string),address([],string),phone([],string)?,email([],string)+).
translate:-
xml2pro('addressbook.xml',Xml),
process(Xml,NewXml),
pro2xml(NewXml,'addressbook2.xml').
process(A,NewA):-
A =*= addressbook([],A2),
records_with_email(A2,A3),
newdoc(addressbook,[],A3,NewA).
records_with_email(<_,X::tr,S2>,<X,S3>):-!,
records_with_email(S2,S3).
records_with_email(_,<>).
In this example types act like filters for the data.
Example 3. Given
document bibs.xml containing a list of
books, create a new document books published by Addison-Wesley after
1991, including their year and title:
translate:-
xml2pro('./examples-xquery/bibs.xml',Xml),
process(Xml,NewXml),
pro2xml(NewXml,'./examples-xquery/bib2.xml').
process(A,NewA):-
bib([],A2) =~= A,
query_pub(A2,A3),
newdoc(bib,[],A3,NewA).
query_pub(<_,book([attribute(year,Y)],title([],T),_,publisher([],'Addison-Wesley'),_),S1>,
<book([attribute(year,Y)],title([],T)),S2>):-
var(S2),
atom_number(Y,Yn),Yn>1991,!,
query_pub(S1,S2).
query_pub(_,<>).
The result is:
<bib>
<book year=1994>
<title>TCP/IP
Illustrated</title>
</book>
<book year=1992>
<title>Advanced Programming
in the Unix environment</title>
</book>
</bib>
Example 4. Given the
files bibs.xml and reviews.xml, both containing entries of
books, create a new file with the prices on both files for each book:
translate:-
xml2pro('./examples-xquery/bibs.xml',Bib),
xml2pro('./examples-xquery/reviews.xml',Rev),
process(Bib,Rev,NewXml),
pro2xml(NewXml,'./examples-xquery/prices.xml').
process(<bib([],B)>,<reviews([],R)>,NewA):-
findall(F,query_pub(B,R,F),FL),
newdoc(books_with_prices,[],FL,NewA).
query_pub(B,R,book_with_price([],title([],T),price_bstore2([],P2),price_bstore1([],P1))):-
<_,book(_,title([],T),_,price([],P1)),S1> =~=
B,
<_,entry([],title([],T),price([],P2),_),S2>
=~= R.
The result is:
<books-with-prices> <book-with-prices> <title>TCP/IP Illustrated</title> <price-bstore2>65.95</price-bstore2> <price-bstore1>65.95</price-bstore1> </book-with-prices> <book-with-prices> <title>Advanced Programming in the Unix environment</title> <price-bstore2>65.95</price-bstore2> <price-bstore1>65.95</price-bstore1> </book-with-prices> <book-with-prices> <title>Data on the Web</title> <price-bstore2>34.95</price-bstore2> <price-bstore1>39.95</price-bstore1> </book-with-prices> </books-with-prices>
Example 5. In the
document prices.xml, find the
minimum price for each book, in
the form of a "minprice" element with the book title as its title
attribute:
translate:-
xml2pro('./examples-xquery/prices.xml',Pri),
setof(X,min_price(Pri,X),NewXml),
newdoc(results,[],NewXml,F),
pro2xml(F,'./examples-xquery/min-prices.xml').
min_price(<prices([],Books)>,minprice([attribute(title,T)],price([],M))):-
<_,book([],title([],T),_),_> =~= Books,
findall(Price,book_price(T,Books,Price),PL),
min(PL,M).
book_price(T,<_,book([],title([],T),_,price([],P)),_>,P).
The result is:
<results> <minprice title="Advanced Programming in the Unix environment"> <price>65.95</price> </minprice> <minprice title="TCP/IP Illustrated"> <price>65.95</price> </minprice> <minprice title="Data on the Web"> <price>34.95</price> </minprice> </results>
Example 6. This use
case is based on a medical report using the HL7 Patient Record
Architecture. Given this report1.xml,
find what happened between the first Incision and the second
Incision and write the result in a file named critical.xml:
translate:-
xml2pro('./examples-xquery/report1.xml',Rep),
deep(<incision(_),Critical,incision(_)>,Rep),
newdoc(critical_sequence,[],Critical,FL),
pro2xml(FL,'./examples-xquery/critical.xml').
The reult is:
<critical_sequence>
The fascia was identified
and<action> #2 0 Maxon stay sutures were placed on each side of
the midline.</action>
</critical_sequence>
Example 7.
Given document book.xml, prepare a
(flat) figure list for it, creating new file figlist.xml where all the figures and
their titles. Preserve the original attributes of each <figure>
element, if any.
translate:-
xml2pro('./examples-xquery/book.xml',Book),
findall(figure(A,title([],T)),deep(figure(A,title([],T),_),Book),Fig),
newdoc(figlist,[],Fig,FL),
pro2xml(FL,'./examples-xquery/figlist.xml').
The result is:
<figlist>
<figure height=400
width=400>
<title>
Traditional client/server architecture
</title>
</figure>
<figure height=200
width=500>
<title>
Graph representations of structures
</title>
</figure>
<figure height=250
width=400>
<title>
Examples of Relations
</title>
</figure>
</figlist>
Example 8. Given file string.xml with a list of news, find
the titles of all news items where the string "Foobar Corporation"
appears in the title.
translate:-
xml2pro('./examples-xquery/string.xml',XML),
findall(T,foobar(XML,T),LT).
foobar(XML,title([],T)):-
deep(news_item([],title([],T),_),XML),
substring('Foobar Corporation',T),
write('<title>'),write(T),write('</title>'),nl.
The result is:
<title>Foobar Corporation releases its new line of Foo products today</title> <title>Foobar Corporation is suing Gorilla Corporation for patent infringement </title>
Example 9. Given the
document candidates.xml, containing a
list of candidates to
a job, select the candidates with two or more previous jobs in their
curriculum:
:- type jobs --->
previous_job([],name([],string),address([],string)){2,unbounded}.
select(N):-
xml2pro('candidates.xml',Can),
doc([],_,person([],name([],N),X::jobs),_) =~=
Can.
The result is:
N = 'David Pereira'
Example 10. In this example we have
two XML files, a simple text.xml
file conforming to text.dtd
and a bib.xml file with simple references conforming to bib.dtd.
Our text.xml
<ref> elements contain author names which appear in the
<author> element of bib.xml.
Our goal is to process text.xml
and bib.xml
and generate new text2.xml
and bib2.xml
files. The text2.xml
file is almost the same than text.xml
but <ref> elements are replaced by new <i>
elements where the content is replaced by a number. This number
represents the index of that reference ordered by author within the
document. The
bib2.xml contains only the references appearing in text.xml,
ordered by author, and with a label element with the corresponding
number that occurs in the text2.xml.
The program follows:
:-use_module([xcentric,xml2prolog,prolog2xml]).
:-type t2 ---> string; ref([],string); b([],string).
:-type t ---> t2*.
:-type i2 ---> string; i([],string); b([],string).
:-type i ---> i2*.
:-type str ---> string.
:-type bib --->
bibliography([],bib([],author([],string),name([],string))*).
run:-
xml2pro('text.xml',T),
process(T).
process(T):-
T =*= text([],CT),
process2(CT,T2,[],Refs),
xml2pro('bib.xml',B),
add_bib(Refs,B,BibXML,1),
newdoc(bibliography,[],BibXML,NewBIB),
newdoc(text,[],T2,NewText),
pro2xml(NewText,'text2.xml'),
pro2xml(NewBIB,'bib2.xml').
process2(<>,<>,L,L).
process2(A,B,L,RRefs):-
A::t =*= <X,ref([],R),Y>,
B::i =*=
<X,i([],NewVar::str),Y2>,
insert_sorted(R,NewVar,L,Refs),
process2(Y,Y2,Refs,RRefs).
process2(S,S,L,L).
add_bib([],_,[],_).
add_bib([(A,AI)|Refs],B,[label([],AI),author([],A),name([],N)|XML],I):-
B::bib =*=
bibliography([],_,bib([],author([],A),name([],N)),_),
I1 is I + 1,
atom_chars(I,AI),
add_bib(Refs,B,XML,I1).
insert_sorted(X,Var,[],[(X,Var)]).
insert_sorted(X,Var,[(Y,Z)|R],[(X,Var),(Y,Z)|R]):-
strcmp(X,Y,I),
I < 0,!.
insert_sorted(X,Var,[(Y,Z)|R1],[(Y,Z)|R2]):-
insert_sorted(X,Var,R1,R2).
strcmp(S1,S2,I):-
string_to_list(S1,L1),
string_to_list(S2,L2),
lcomp(L1,L2,I).
lcomp([],[],0).
lcomp([X|R1],[X|R2],N):-!,
lcomp(R1,R2,N).
lcomp([X|_],[Y|_],N):-
N is X - Y.
The run
predicate starts the translation process. In a first step, the
process2 predicate translates the original text into a new
one where the <ref>
elements are replaced by new <i>
elements and the content is replaced by a new free variable. At the
same time pairs (Ref_content,FreeVariable)
(corresponding to the author in <ref>
and the new variable in <i> respectively)
are inserted in a list ordered by Ref_content.
At the end we have a list of pairs ordered by author. In a second step,
add_bib queries the bibliography file, retrieving the
references found in the text and replacing the free variables with
their definite content, thus, avoiding a second processing of the text
file.
This example emphasizes some advantages of logic
programming languages for XML processing; it shows an highly
declarative and compact code and the advantages of using logic
variables that permit to solve the problem by processing the text.xml
document only once. Types guarantee correctness of values given as
input and the results of processing.
|