| Minerva supports the manipulation (read/modify/write) of XML terms.
There exist four predicates for reading and writing XML terms.
- write_xml/1/2
- read_xml/2/3
There are also a couple of predicates for converting lowlevel
XML terms to highlevel MINERVA terms and vice versa.
- term2xml/3
- term2xmldoc/3
- xml2term/3
- xmldoc2term/3
Type definitions for XML terms
The conversion predicates (between highlevel and lowlevel XML terms) need
a type description of the XML term, to do their job. The type definition has
the following format:
TypeDefinition =
MarkupName(AttributeAndSubElementType ...)
% example: addressbook(type=enum([private,business]), any * Address)
AttributeAndSubElementType =
AttributeType
AttributeAndSubElementType =
ElementType
AttributeType =
AttributeName = BasicType
% example: type = enum([private,business])
AttributeType =
AttributeName = opt(BasicType,DefaultValue)
% example: language = opt(atom, english)
ElementType =
(ElementType, ElementType)
% example: (title(-atom),author(firstname(-atom),name(-atom)),price(-number))
ElementType =
(ElementType; ElementType)
% example: (book(title(-atom),author(Autor));journal(title(-atom),volume(-integer)))
ElementType =
Count * ElementType
% example: book(title(-atom),author(Autor),(0,5)*coautor(Autor))
ElementType =
- BasicType
% example: year(-integer)
ElementType =
TypeDefinition
Count =
(Min,Max)
Count =
Integer
% "N * Type" is equivalent to "(N,N) * Type"
Count =
any
% "any * Type" is equivalent to "(0,inf) * Type"
Count =
opt
% "any * Type" is equivalent to "(0,1) * Type"
Count =
some
% "any * Type" is equivalent to "(1,inf) * Type"
Min =
NonNegativeInteger
Max =
NonNegativeInteger
Max =
inf
BasicType =
atom
BasicType =
integer
BasicType =
float
BasicType =
number
BasicType =
boolean
BasicType =
enum([Name, ...])
Examples:
The handling of XML terms is easy as you can see from the following example.
Suppose you have collected the addresses of your friends in a XML file.
This shall have the following format:
John
35
Henriette
27
Now you want to read the addressbook in MINERVA. Open the
the XML file with open/3 and read the XML term with
read_xml/2.
main([XmlFilename]) :-
open(XmlFilename, read, XmlStream),
read_xml(XmlStream, XmlTerm),
close(XmlStream),
writeq(XmlTerm),
nl.
When calling this program you will get the following output.
document([xml([version = '1.0'])],
element(addressbook,[],[
element(address,[telno = '1234567'],[
element(name,[],[chardata('John')]),
element(age,[],[chardata('35')])]),
element(address,[telno = '3456789',email = 'henriette@ifcomputer.com'],[
element(name,[],[chardata('Henriette')]),
element(age,[],[chardata('27')])])]),[])
So, you read the XML file and got the content of this file as MINERVA term.
You can examine this term, manipulate it and write it back to another file.
For example you may have two address books of the same format, one containing
the addresses of your friends and the another containing the addresses
of your business partners. You may decide to merge the two
address books into one book.
main([Friends,BusinessPartner,NewAddrBook]) :-
read_xmlfile(Friends,Book_1),
read_xmlfile(BusinessPartner,Book_2),
merge_books(Book_1, Book_2, Book),
write_xmlfile(NewAddrBook, Book).
read_xmlfile(Filename, XmlTerm) :-
open(Filename, read, Stream),
read_xml(Stream, XmlTerm),
close(Stream).
merge_books(
document(_,Addr_1,_),
document(_,Addr_2,_),
document([xml([version = '1.0'])], Elements, [])) :-
append(Addr_1, Addr_2, Addr),
sort(Addr, Elements).
write_xmlfile(Filename, XmlTerm) :-
open(Filename, write, Stream),
write_xml(Stream, XmlTerm),
close(Stream).
Or you want to print all persons sortet by their age.
You could do it as follows.
main([AddrBook,Person]) :-
read_xmlfile(AddrBook, Book),
findall(person(Age,Name), getperson(Book, Name, Age), List),
sort(List, SortedList),
writeq(SortedList),
nl.
read_xmlfile(Filename, XmlTerm) :-
open(Filename, read, Stream),
read_xml(Stream, XmlTerm),
close(Stream).
getperson(document(_,Elements,_), Name, Age) :-
member(Element, Elements),
Element = element(address,Attributes,[NameElem,AgeElem]),
AgeElem = element(age,_,[chardata(AgeString)]),
atom_number(AgeString, Age),
NameElem = element(name,_,[chardata(Name)]).
The last example showed that the manipulation of lowlevel terms is quite
complex (see getperson/2).
Therefore MINERVA offers some predicates to convert lowlevel XML terms
in a more convenient format. Using these predicates the last example could
be implemented as follows.
main([AddrBook,Person]) :-
read_xmlfile(AddrBook, XmlTerm),
booktype(BookType),
xmldoc2term(BookType, XmlTerm, Book),
findall(person(Age,Name), getperson(Book, Name, Age), List),
sort(List, SortedList),
writeq(SortedList),
nl.
booktype(addressbook(any * AddressType)) :-
AddressType = address(
telno=atom, % Attribute 'telno'
email=opt(atom,''), % Optional attribute 'email' (defaults to '')
name(-atom),
age(-integer))). % subelements 'name' and 'age'
read_xmlfile(Filename, XmlTerm) :-
open(Filename, read, Stream),
read_xml(Stream, XmlTerm),
close(Stream).
getperson(addressbook(AddressList), Name, Age) :-
member(address(_, _, name(Name), age(Age)), AddressList).
|