Περιγραφή δεδομένων με 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 />

Προσδιορισμοί

Παράδειγμα:
<city country="el" id="HER">
<name>Hrakleio</name>
</city>
Ως προσιδιορισμούς συνιστάται να γράφουμε απλές τιμές που ορίζουν:

Οντότητες και σχόλια

Οι παρακάτω οντότητες (entities) μπορούν να οριστούν περιφραστικά:
ΟντότηταΣύνταξη XML
<&lt;
&&amp;
>&gt;
"&quot;
'&apos;

Σχόλια μέσα σε ένα έγγραφο 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());
            }
    }

    Σύνταξη κανονικών εκφράσεων

    Τα παρακάτω σύμβολα έχουν ειδικό νόημα:
    ^
    Αρχή της γραμμής
    $
    Τέλος της γραμμής
    .
    Οποιοδήποτε γράμμα
    [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}
    Μη ελληνικό γράμμα

    Χρήση κανονικών εκφράσεων

    Παράδειγμα: Εύρεση κανονικών εκφράσεων σε αρχείο

    /*
     * 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);
            }
    }

    Βιβλιογραφία