Περιγραφή δεδομένων με XML και κανονικές εκφράσεις
Διομήδης Σπινέλλης
Τμήμα Διοικητικής Επιστήμης και Τεχνολογίας
Οικονομικό Πανεπιστήμιο Αθηνών
dds@aueb.gr
Βάσεις της XML
Έγγραφα XML
Παράδειγμα: ένα στοιχείο με κείμενο
<city>Larisa</city>
Παράδειγμα: στοιχείο με περιεχόμενο άλλα στοιχεία
<?xml version="1.0" encoding="US-ASCII" ?>
<city_info>
<name>Larisa</name>
<area_code>241</area_code>
<latitude>39.38</latitude>
<longitude>-22.25</longitude>
<country>Greece</country>
</city_info>
Παράδειγμα: κενό στοιχείο
<alumnus />
Προσδιορισμοί
- Κάθε ετικέτα αρχής μπορεί να περιέχει και πρόσθετους
προσδιορισμούς (attributes)
- Οι προσδιορισμοί ορίζονται με τη σύνταξη όνομα=τιμή μέσα στην ετικέτα
- Η τιμή πρέπει να βρίσκεται μέσα σε μονά ή διπλά εισαγωγικά
- Για κάθε όνομα μπορεί να οριστεί ένας μόνο προσδιορισμός
Παράδειγμα:
<city country="el" id="HER">
<name>Hrakleio</name>
</city>
Ως προσιδιορισμούς συνιστάται να γράφουμε απλές τιμές που ορίζουν:
- Μεταδεδομένα
- Κλειδιά
- Συσχετίσεις
Οντότητες και σχόλια
Οι παρακάτω οντότητες (entities)
μπορούν να οριστούν περιφραστικά:
Οντότητα | Σύνταξη XML |
< | < |
& | & |
> | > |
" | " |
' | ' |
Σχόλια μέσα σε ένα έγγραφο XML γράφονται ως
<!-- περιεχόμενο -->
Ορισμός τύπου εγγράφων
Υποστηρίζονται οι παρακάτω ορισμοί:
- Απλοί χαρακτήρες (parsed character data)
-
<!ELEMENT name (#PCDATA)>
Ένα στοιχείο
<!ELEMENT student (person_data)>
Ακολουθία στοιχείων
<!ELEMENT person_data (name, surname)>
Κανένα ή ένα στοιχείο
<!ELEMENT person_name (given_name, initial?, last_name)>
Μηδέν ή περισσότερα στοιχεία
<!ELEMENT owned_cars (car*)>
Ένα ή περισσότερα στοιχεία
<!ELEMENT course_lecturer (person_data+)>
Επιλογή στοιχείων
<!ELEMENT engine (two_stroke | four_stroke | wankel | rotary)>
Χρήση παρενθέσεων
<!ELEMENT person_details (name, surname, (vat_number | id_number))>
Κενό περιεχόμενο
<!ELEMENT alumnus EMPTY>
Τυχαίο περιεχόμενο
<!ELEMENT text ANY>
Παράδειγμα - DTD
<!--
-
- Document Type Description for the projects
-
- $Id: project.dtd,v 1.2 2004/01/24 20:20:04 bkarak Exp $
-
-->
<!ELEMENT project (
shortname,
projtitle,
startdate?,
enddate,
web_site?,
our_budget?,
total_budget?,
funding_agency?,
funding_programme?,
project_code?,
partner*,
logo?,
description
)>
<!ELEMENT projtitle (#PCDATA)>
<!ELEMENT our_budget (#PCDATA)>
<!ELEMENT total_budget (#PCDATA)>
<!ELEMENT funding_agency (#PCDATA)>
<!ELEMENT funding_programme (#PCDATA)>
<!ELEMENT project_code (#PCDATA)>
<!ELEMENT web_site (#PCDATA)>
<!ELEMENT startdate (#PCDATA)>
<!ELEMENT enddate (#PCDATA)>
<!ELEMENT shortname (#PCDATA)>
<!ELEMENT logo (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT partner (shortname, country, web_site?)>
<!ELEMENT shortname (#PCDATA)>
<!ELEMENT country (#PCDATA)>
Παράδειγμα - αντίστοιχη XML
<?xml version="1.0"?>
<project>
<shortname>mExpress</shortname>
<projtitle>mobile in-EXhibition PRovision of Electronic Support Services</projtitle>
<startdate>20020305</startdate>
<enddate>20040401</enddate>
<web_site>http://mexpress.intranet.gr/</web_site>
<our_budget>328 EUR</our_budget>
<total_budget>3,493 EUR</total_budget>
<funding_agency>European Commission</funding_agency>
<funding_programme>IST</funding_programme>
<project_code>IST-2001-33432</project_code>
<partner>
<shortname>Intracom</shortname>
<country>EL</country>
<web_site>http://www.intracom.gr</web_site>
</partner>
<partner>
<shortname>Ericsson</shortname>
<country>DK</country>
<web_site>http://www.ericsson.com/</web_site>
</partner>
<partner>
<shortname>ELISA</shortname>
<country>FIN</country>
<web_site>http://www.elisa.com</web_site>
</partner>
<partner>
<shortname>POULIADIS</shortname>
<country>EL</country>
<web_site>http://www.pouliadis.gr</web_site>
</partner>
<partner>
<shortname>SSF</shortname>
<country>FIN</country>
<web_site>http://www.ssf.fi/</web_site>
</partner>
<partner>
<shortname>HUT</shortname>
<country>FIN</country>
<web_site>http://www.hut.fi</web_site>
</partner>
<partner>
<shortname>FFC</shortname>
<country>FIN</country>
</partner>
<partner>
<shortname>ROTA</shortname>
<country>EL</country>
<web_site>http://www.rota.gr</web_site>
</partner>
<logo>../images/p_mexpress.gif</logo>
<description>
mEXPRESS aims to exploit the technological opportunities arising from
evolution in the areas of wireless networks and positioning mechanisms in
order to support and facilitate the professional exhibition industry in
a context-aware manner. It will contribute to the economic development of
the Community by providing means for efficient operation and interaction
in information-rich environments such as exhibitions, and significantly
enhancing promotional activities and business communications. The mEXPRESS
project will provide an integrated mediation platform (mEXPRESS Service
Provider) oriented to exhibition shows and events.
</description>
</project>
Ορισμός τύπων προσδιορισμών
Οι προδιορισμοί που επιτρέπονται σε ένα στοιχείο ορίζονται με στοιχεία
της μορφής
<!ATTLIST όνομα_στοιχείου
όνομα_προσδιορισμού τύπος_προσδιορισμού περιορισμός
...
>
Υποστηρίζονται μεταξύ άλλων οι παρακάτω τύποι προσδιορισμού
- Χαρακτήρες
- CDATA
- Απαρίθμηση
- (επιλογή1 | επιλογή2 | ...)
- Κλειδί
- ID
- Αναφορά σε κλειδί
- IDREF
- Αναφορά σε κλειδιά
- IDREFS
Οι πιο χρήσιμοι περιορισμοί προσδιορισμών είναι:
- #IMPLIED
- Προαιρετικός προσδιορισμός
- #REQUIRED
- Υποχρεωτικός προσδιορισμός
Παράδειγμα - DTD
<!ATTLIST project
id ID #REQUIRED
contact CDATA #IMPLIED
scientific_coordinator CDATA #IMPLIED
project_manager CDATA #IMPLIED
group CDATA #REQUIRED
international (yes | no) #REQUIRED
type (consulting | rtd | training | dissemination) #REQUIRED
>
Παράδειγμα - XML
<?xml version="1.0"?>
<project
id="p_mexpress"
group="g_sense g_wrc"
scientific_coordinator="m_dds"
contact="m_pateli"
international="yes"
type="rtd"
project_manager="m_pateli"
>
<!-- ... -->
</project>
Μετασχηματισμοί
Παράδειγμα XSLT
<?xml version="1.0"?>
<!-- Apply using
xml tr project.xslt mexpress.xml
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="project">
<h1>
<xsl:value-of select="shortname" />
-
<xsl:value-of select="projtitle" />
</h1>
<!-- Show Logo -->
<xsl:element name="img">
<xsl:attribute name="src"><xsl:value-of select="logo" /></xsl:attribute>
</xsl:element>
<br /> <br />
<!-- Project Summary information -->
<xsl:if test="count(project_code) != 0">
Project Code:
<xsl:value-of select="project_code" />
<xsl:if test="@international = 'yes'">
(International)
</xsl:if>
<br/>
</xsl:if>
<xsl:if test="count(funding_programme) != 0">
Funding programme: <xsl:value-of select="funding_programme" />
<br />
</xsl:if>
<xsl:if test="count(funding_agency) != 0">
Funding Agency: <xsl:value-of select="funding_agency" />
<br />
</xsl:if>
<xsl:if test="@type != ''">
Project type:
<xsl:choose>
<xsl:when test="@type = 'rtd'">RTD</xsl:when>
<xsl:when test="@type = 'consulting'">Consulting</xsl:when>
<xsl:when test="@type = 'training'">Training</xsl:when>
<xsl:when test="@type = 'dissemination'">Dissemination</xsl:when>
</xsl:choose>
<br />
</xsl:if>
<xsl:if test="count(web_site) != 0">
Web site:
<xsl:element name="a">
<xsl:attribute name="href"><xsl:value-of select="web_site"/></xsl:attribute>
<xsl:value-of select="web_site" />
</xsl:element>
<br />
<br />
</xsl:if>
<xsl:if test="count(our_budget) != 0">
ELTRUN budget: <xsl:value-of select="our_budget" />
<br />
</xsl:if>
<xsl:if test="count(total_budget) != 0">
Total budget: <xsl:value-of select="total_budget" />
<br />
</xsl:if>
<br />
</xsl:template>
</xsl:stylesheet>
Αποτέλεσμα HTML
mExpress
-
mobile in-EXhibition PRovision of Electronic Support Services
Project Code:
IST-2001-33432
(International)
Funding programme: IST
Funding Agency: European Commission
Project type:
RTD
Web site:
http://mexpress.intranet.gr/ (http://mexpress.intranet.gr/)
ELTRUN budget: 328 EUR
Total budget: 3,493 EUR
|
Το μοντέλο αντικειμένων εγγράφων
Η υλοποίηση του μοντέλου αντικειμένων εγγράφων στη Java
Η επεξεργασία ενός αρχείου XML γίνεται μέσω ενός συντακτικού αναλυτή
DocumentBuilder
που παράγεται από την κλάση DocumentBuilderFactory
// Create the DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// Create the document builder
DocumentBuilder db = dbf.newDocumentBuilder();
Η μέθοδος parse του συντακτικού αναλυτή DocumentBuilder επιστρέφει ένα
αντικείμενο που υποστηρίζει τη διεπαφή Document.
Μπορεί να κληθεί με όρισμα:
Παράδειγμα: υπολογισμός μέσου όρου
/*
* Print the average value of the specified node
* D. Spinellis, January 2004
*/
import javax.xml.parsers.*;
import java.io.*;
import org.w3c.dom.*;
class Average {
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("Usage: Average element file");
System.exit(1);
}
Document doc = null;
try {
// Create the DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// Create the document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// Create DOM document from the file
doc = db.parse(new File(args[1]));
} catch (Exception e) {
System.err.println("Parsing failed: " + e);
System.exit(1);
}
NodeList grades = doc.getElementsByTagName(args[0]);
double sum = 0.0;
for (int i = 0; i < grades.getLength(); i++) {
String grade = grades.item(i).getFirstChild().getNodeValue();
sum += (new Integer(grade)).doubleValue();
}
System.out.println(sum / grades.getLength());
}
}
Σύνταξη κανονικών εκφράσεων
- Μια κανονική έκφραση (regular expression) επιτρέπει τον ορισμό σύνθετων συμβολοσειρών με δηλωτικό τρόπο.
- Η κανονική έκφραση αποτελείται από
- γράμματα (που παριστάνουν τον εαυτό τους) και
- ειδικά σύμβολα
Τα παρακάτω σύμβολα έχουν ειδικό νόημα:
- ^
- Αρχή της γραμμής
- $
- Τέλος της γραμμής
- .
- Οποιοδήποτε γράμμα
- [abc]
- Ένα από τα γράμματα a, b, ή c
- [a-z]
- Ένα από τα γράμματα a μέχρι z
- [^abc]
- Οποιοδήποτε γράμμα εκτός από τα a, b, και c.
- Έκφραση?
- Η έκφραση μία ή καμία φορά
- Έκφραση*
- Η έκφραση μηδέν ή περισσότερες φορές
- Έκφραση+
- Η έκφραση μία ή περισσότερες φορές
- Έκφραση{n}
- Η έκφραση n φορές
- Έκφραση{n,}
- Η έκφραση τουλάχιστον n φορές
- Έκφραση{n,m}
- Η έκφραση τουλάχιστον n αλλά
όχι περισσότερες από m φορές
- Έκφραση1|Έκφραση2
- Η έκφραση1 ή η έκφραση2
- (Έκφραση)
- Το περιεχόμενο στην παρένθεση
- \1 \2 ... \n
- To περιεχόμενο της νοστής παρένθεσης
- \0nnn
- Χαρακτήρας με οκταδική τιμή nnn
- \0xnnn
- Χαρακτήρας με δεκαεξαδική τιμή nnn
- \\
- Ο χαρακτήρας \
- \t
- Ο χαρακτήρας tab
- \n
- Ο χαρακτήρας newline
- \r
- Ο χαρακτήρας carriage return
- \a
- Ο χαρακτήρας alert
- \f
- Ο χαρακτήρας form feed
- \e
- Ο χαρακτήρας escape
- \cx
- Ο χαρακτήρας control-x (a-z)
- \d
- Ψηφίο
- \D
- Μη ψηφίο
- \s
- Κενό
- \S
- Μη κενό
- \p{InGreek}
- Ελληνικό γράμμα: όνομα μπλοκ http://www.unicode.org/Public/3.0-Update/Blocks-3.txt (http://www.unicode.org/Public/3.0-Update/Blocks-3.txt)
- \P{InGreek}
- Μη ελληνικό γράμμα
Χρήση κανονικών εκφράσεων
- Στη Java οι κανονικές εκφράσεις μπορούν να οριστούν
με τη βοήθεια της κλάσης Pattern.
- Η μέθοδος Pattern.compile(String re) επιστρέφει ένα αντικείμενο
τύπου Pattern που είναι η κανονική έκφραση re μεταγλωττισμένη.
- Η μέθοδος matcher(String s) του παραπάνω αντικειμένου επιστρέφει
ένα αντικείμενο m τύπου Matcher το οποίο μπορεί να ταιριάξει τη συμβολοσειρά
re με το αντικείμενο s.
- Στο αντικείμενο m:
- η μέθοδος m.find() προσπαθεί να ταιριάξει την κανονική έκφραση σε οποιαδήποτε θέση
- η μέθοδος m.matches() προσπαθεί να ταιριάξει την κανονική έκφραση από
την αρχή μέχρι το τέλος της συμβολοσειράς
Και οι δύο μέθοδοι επιστρέφουν true αν η συμβολοσειρά ταιρίαζει με την
κανονική έκφραση.
- Η μέθοδοι m.start() και m.end() επιστρέφουν τις θέσεις της
συμβολοσειράς που ταίριαξε με την κανονική έκφραση.
Παράδειγμα: Εύρεση κανονικών εκφράσεων σε αρχείο
/*
* Globally match regular expression and print
* Modelled after the Unix command with the same name
* D. Spinellis, January 2004
*/
import java.util.regex.*;
import java.io.*;
class Grep {
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("Usage: Grep pattern file");
System.exit(1);
}
Pattern cre = null; // Compiled RE
try {
cre = Pattern.compile(args[0]);
} catch (PatternSyntaxException e) {
System.err.println("Invalid RE syntax: " + e.getDescription());
System.exit(1);
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(args[1])));
} catch (FileNotFoundException e) {
System.err.println("Unable to open file " + args[1] + ": " + e.getMessage());
System.exit(1);
}
try {
String s;
while ((s = in.readLine()) != null) {
Matcher m = cre.matcher(s);
if (m.find())
System.out.println(s);
}
} catch (Exception e) {
System.err.println("Error reading line: " + e.getMessage());
System.exit(1);
}
}
}
Παράδειγμα:
java Grep "abo" /usr/dict/words
...
sabotage
seaboard
taboo
thereabouts
turnabout
vagabond
whereabout
...
java Grep "^abo" /usr/dict/words
aboard
abode
abolish
abolition
abominable
abominate
aboriginal
java Grep bent /usr/dict/words
absorbent
bent
benthic
debenture
incumbent
recumbent
java Grep "bent$" /usr/dict/words
absorbent
bent
incumbent
recumbent
java Grep "[^AEIOUYaeiouy]{5,}" /usr/dict/words
angstrom
Armstrong
birthplace
bremsstrahlung
corkscrew
Dijkstra
downstream
hardscrabble
jockstrap
Knightsbridge
lengthly
Nietzsche
nightclub
offspring
postscript
Rothschild
...
java Grep "(.)(.)(.)\3\2\1" /usr/dict/words
braggart
Brenner
collocation
diffident
dissident
glossolalia
grammar
grammarian
installation
staccato
suffuse
Διαίρεση συμβολοσειρών με πρότυπα
Παράδειγμα: επεξεργασία αρχείων πρόσβαση σε ιστοσελίδες
/*
* Collect and print Web statistics
* D. Spinellis, January 2004
*/
import java.util.*;
import java.util.regex.*;
import java.io.*;
class WebStats {
/**
* Increment the integer value of map's member by 1
* The member is obtained by using the matcher to extract
* the specified group from the string s
*/
static void increment(Map map, String s, Matcher m, int group) {
String member = s.substring(m.start(group), m.end(group));
Integer i = (Integer)map.get(member);
if (i == null)
i = new Integer(1);
else
i = new Integer(i.intValue() + 1);
map.put(member, i);
}
/** List the contents of the given map */
static void list(String title, Map map) {
System.out.println("\n" + title);
Set s = map.entrySet();
Iterator i;
for (i = s.iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry)i.next();
System.out.println(e.getValue() + " " + e.getKey());
}
}
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("Usage: WebStats file");
System.exit(1);
}
Pattern cre = null; // Compiled RE
try {
// A standard log line is a line like:
// 192.168.136.16 - - [26/Jan/2004:19:45:48 +0200] "GET /c136.html HTTP/1.1" 200 1674 "http://office/c120.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007"
cre = Pattern.compile(
"([-\\w.]+)\\s+" + // 1. Host
"([-\\w]+)\\s+" + // 2. Logname
"([-\\w]+)\\s+" + // 3. User
"\\[(\\d+)/" + // 4. Date
"(\\w+)/" + // 5. Month
"(\\d+):" + // 6. Year
"(\\d+):" + // 7. Hour
"(\\d+)" + // 8. Minute
"([^]]+?)\\]\\s+" + // 9. Rest of time
"\"([-\\w]+)\\s*" + // 10. Request verb
"([^\\s]*)" + // 11. Request URL
"([^\"]*?)\"\\s+" + // 12. Request protocol etc.
"(\\d+)\\s+" + // 13. Status
"([-\\d]+)\\s+" + // 14. Bytes
"\"([^\"]*)\"\\s+" + // 15. Referrer URL
"\"([^\"]*)\"" // 16. Client
);
} catch (PatternSyntaxException e) {
System.err.println("Invalid RE syntax: " + e.getDescription());
System.exit(1);
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(args[0])));
} catch (FileNotFoundException e) {
System.err.println("Unable to open file " + args[1] + ": " + e.getMessage());
System.exit(1);
}
HashMap host = new HashMap();
HashMap hour = new HashMap();
HashMap request = new HashMap();
HashMap referrer = new HashMap();
try {
String s;
while ((s = in.readLine()) != null) {
Matcher m = cre.matcher(s);
if (!m.matches())
System.out.println("Invalid line: " + s);
else {
increment(host, s, m, 1);
increment(hour, s, m, 7);
increment(request, s, m, 11);
increment(referrer, s, m, 15);
}
}
} catch (Exception e) {
System.err.println("Error reading line: " + e.getMessage());
System.exit(1);
}
list("Host Access Counts", host);
list("Hourly Access Counts", hour);
list("Request URL Access Counts", request);
list("Referrer URL Access Counts", referrer);
}
}
Βιβλιογραφία
- Rogers Cadenhead και Laura Lemay
Πλήρες εγχειρίδιο της Java 2 Εκδόσεις Μ. Γκιούρδας, Αθήνα 2003.
Κεφάλαια 21 και 28.
- A. V. Aho and M. J.
Corasick.
Efficient string matching: an aid to bibliographic search.
Communications of the ACM, 18(6):333–340, 1975.
- Jeffrey E. Friedl and
Andy Oram, editors.
Mastering Regular Expressions: Powerful Techniques for Perl and Other
Tools.
O'Reilly and Associates, Sebastopol, CA, second edition, 2002.
- Eric Hamilton.
Literate programming—expanding generalized regular expressions.
Communications of the ACM, 31(12):1376–1385, December 1988.
- Elliotte Rusty Harold
and W. Scott Means.
XML
in a Nutshell.
O'Reilly and Associates, Sebastopol, CA, 2001.
- Andrew Hume.
Grep wars: The strategic search initiative.
In Peter Collinson, editor, Proceedings of the EUUG Spring 88
Conference, pages 237–245, Buntingford, UK, 1988. European UNIX
User Group.
- Ken Thompson.
Programming techniques: Regular expression search algorithm.
Communications of the ACM, 11(6):419–422, 1968.
(doi:10.1145/363347.363387 (http://dx.doi.org/10.1145/363347.363387))