diff --git a/Doc/course.xml b/Doc/course.xml index 811c61c7470e354617e2304faa2f170d0021eca5..fba191e379944e197f3ea04da3ad50a1669aee42 100644 --- a/Doc/course.xml +++ b/Doc/course.xml @@ -7666,8 +7666,8 @@ public class ElementCount { redefine only those methods corresponding to events actually being handled by the application in question.</para> - <qandaset defaultlabel="qanda" xml:id="exercise_saxAttrib"> - <title>Reading XML attributes</title> + <qandaset xml:id="sda1SaxReadAttributes"> + <title>SAX and attribute values</title> <qandadiv> <qandaentry> @@ -7703,19 +7703,183 @@ public class AttribEventHandler extends DefaultHandler { }</programlisting> </answer> </qandaentry> + </qandadiv> + </qandaset> - <qandaentry xml:id="saxRdbms"> + <qandaset xml:id="sda1QandaElementNames"> + <title>Element lists of arbitrary XML documents.</title> + + <qandadiv> + <qandaentry> <question> - <label>SAX processing with RDBMS access.</label> + <para>We reconsider the simple application reading arbitrary + XML documents and providing a list of XML Elements being + contained within:</para> - <para>Implement the example given in <xref - linkend="saxRdbmsAccessPrinciple"/> to produce the output - sketched in <xref linkend="saxPriceOut"/>. You may start by - implementing <emphasis>and testing</emphasis> the following - methods of a RDBMS interfacing class using <trademark - xlink:href="http://electronics.zibb.com/trademark/jdbc/29545026">JDBC</trademark>:</para> + <programlisting>Opening Document +<emphasis role="bold">Opening "catalog"</emphasis> +Content " + " +<emphasis role="bold">Opening "item"</emphasis> +Content "Swinging headset" +Closing "item" +Content " ...</programlisting> + + <para>If an element like e.g. <tag + class="starttag">item</tag> appears multiple times it will + also be written to standard output multiple times.</para> + + <para>We are now interested to get the list of all elements + names being present in an arbitrary XML document. Consider + the following example:</para> + + <programlisting language="xml"><memo> + <from> + <name>Martin</name> + <surname>Goik</surname> + </from> + <to> + <name>Adam</name> + <surname>Hacker</surname> + </to> + <to> + <name>Eve</name> + <surname>Intruder</surname> + </to> + <date year="2005" month="1" day="6"/> + <subject>Firewall problems</subject> + <content> + <para>Thanks for your excellent work.</para> + <para>Our firewall is definitely broken!</para> + </content> +</memo></programlisting> + + <para>The elements <tag class="starttag">to</tag> , <tag + class="starttag">name</tag>, <tag + class="starttag">surname</tag> and <tag + class="starttag">para</tag> both appear multiple times. + Write a SAX application which processes arbitrary XML + documents and creates an alphabetically sorted list of + elements being contained <emphasis role="bold">excluding + duplicates</emphasis>. The intended output for the above + example is: </para> + + <programlisting>List of elements: {content date from memo name para subject surname to }</programlisting> + + <para>The corresponding handler should be implemented in a + re-usable way. Thus if different XML documents are being + handled in succession the list of elements should be erased + prior to processing the current document. Hints:</para> + + <itemizedlist> + <listitem> + <para>Use a <classname>java.util.SortedSet</classname> + instance to collect element names thereby excluding + duplicates.</para> + </listitem> + + <listitem> + <para>The method + <methodname>sax.count.ListTagNamesHandler.startDocument()</methodname> + may be used to initialize your handler.</para> + </listitem> + </itemizedlist> + </question> + + <answer> + <para>A suitable handler reads:</para> + + <programlisting language="java">package sax.count; + +import java.util.SortedSet; +import java.util.TreeSet; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** Reading attributes from element events */ +public class ListTagNamesHandler extends DefaultHandler { - <programlisting language="java">package sax.rdbms; + // A SortedSet by definition does not contain any duplicates. + private SortedSet<String> elementNames = new TreeSet<>(); + + @Override + public void startDocument() throws SAXException { + elementNames.clear(); // May contain elements from a previous run. + } + + public void startElement(String namespaceUri, String localName, + String rawName, Attributes attrs) { + // In case the current element name has already been inserted + // this method call will be silently ignored. + elementNames.add(rawName); + } + + /** + * @return A sorted list of element names of he currently processed XML + * document without duplicates. + */ + public String[] getTagNames() { + return elementNames.toArray(new String[0]); + } +}</programlisting> + + <para>A complete application requires a driver:</para> + + <programlisting language="java">package sax.count; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.XMLReader; + +import sax.stat.v2.MyErrorHandler; + +public class Driver { + + public static void main(String argv[]) throws Exception { + + final SAXParserFactory saxPf = SAXParserFactory.newInstance(); + final SAXParser saxParser = saxPf.newSAXParser(); + final XMLReader xmlReader = saxParser.getXMLReader(); + final ListTagNamesHandler handler = new ListTagNamesHandler(); + xmlReader.setContentHandler(handler); + xmlReader.setErrorHandler(new MyErrorHandler()); + xmlReader.parse("Input/Xml/Memo/message.xml"); + + System.out.print("List of elements: {"); + for (String elementName : handler.getTagNames()) { + System.out.print(elementName + " "); + } + System.out.println("}"); + } +}</programlisting> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + + <section xml:id="sda1SaxRdbms"> + <title>SAX and RDBMS</title> + + <qandaset defaultlabel="qanda" xml:id="exercise_saxAttrib"> + <title>Reading XML attributes</title> + + <qandadiv> + <qandaentry xml:id="saxRdbms"> + <question> + <label>SAX processing with RDBMS access.</label> + + <para>Implement the example given in <xref + linkend="saxRdbmsAccessPrinciple"/> to produce the output + sketched in <xref linkend="saxPriceOut"/>. You may start + by implementing <emphasis>and testing</emphasis> the + following methods of a RDBMS interfacing class using + <trademark + xlink:href="http://electronics.zibb.com/trademark/jdbc/29545026">JDBC</trademark>:</para> + + <programlisting language="java">package sax.rdbms; public class RdbmsAccess { @@ -7731,30 +7895,30 @@ public class RdbmsAccess { } }</programlisting> - <para>You may find it helpful to write a small testbed for - the RDBMS access functionality prior to integrate it into - your <acronym - xlink:href="http://www.saxproject.org">SAX</acronym> - application producing HTML output.</para> - </question> + <para>You may find it helpful to write a small testbed for + the RDBMS access functionality prior to integrate it into + your <acronym + xlink:href="http://www.saxproject.org">SAX</acronym> + application producing HTML output.</para> + </question> - <answer> - <para>We start by creating a suitable RDBMS Table:</para> + <answer> + <para>We start by creating a suitable RDBMS Table:</para> - <programlisting>CREATE SCHEMA AUTHORIZATION midb2 + <programlisting>CREATE SCHEMA AUTHORIZATION midb2 CREATE TABLE Product( orderNo CHAR(10) NOT NULL PRIMARY KEY ,price DECIMAL (9,2) NOT NULL )</programlisting> - <para>Next we feed some toy data:</para> + <para>Next we feed some toy data:</para> - <programlisting>INSERT INTO Product VALUES('x-223', 330.20); + <programlisting>INSERT INTO Product VALUES('x-223', 330.20); INSERT INTO Product VALUES('w-124', 110.40);</programlisting> - <para>Now we implement our RDBMS access class:</para> + <para>Now we implement our RDBMS access class:</para> - <programlisting language="java">package dom.xsl; + <programlisting language="java">package dom.xsl; ... public class DbAccess { @@ -7797,10 +7961,10 @@ public class DbAccess { private Connection conn = null; }</programlisting> - <para>This access layer may be tested independently from - handling catalog instances:</para> + <para>This access layer may be tested independently from + handling catalog instances:</para> - <programlisting language="java">package dom/xsl; + <programlisting language="java">package dom/xsl; public class DbAccessDriver { @@ -7814,12 +7978,12 @@ public class DbAccessDriver { } }</programlisting> - <para>If the above test succeeds we may embed the RDBMS - access layer into our The <acronym - xlink:href="http://www.saxproject.org">SAX</acronym> - handler:</para> + <para>If the above test succeeds we may embed the RDBMS + access layer into our The <acronym + xlink:href="http://www.saxproject.org">SAX</acronym> + handler:</para> - <programlisting language="java">package sax.rdbms; + <programlisting language="java">package sax.rdbms; ... public class HtmlEventHandler extends DefaultHandler{ public void startDocument() { @@ -7861,10 +8025,11 @@ public class HtmlEventHandler extends DefaultHandler{ } private DbAccess dbaccess = new DbAccess(); }</programlisting> - </answer> - </qandaentry> - </qandadiv> - </qandaset> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> </section> <section xml:id="saxValidate"> diff --git a/ws/eclipse/Jdbc/src/main/java/sax/count/Driver.java b/ws/eclipse/Jdbc/src/main/java/sax/count/Driver.java new file mode 100644 index 0000000000000000000000000000000000000000..e09282ff676a0e78ae5b7a104ced073ab881cf03 --- /dev/null +++ b/ws/eclipse/Jdbc/src/main/java/sax/count/Driver.java @@ -0,0 +1,34 @@ +package sax.count; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.XMLReader; + +import sax.stat.v2.MyErrorHandler; + +/** Driver class */ +public class Driver { + + /** + * @param argv + * unused + * @throws Exception + */ + public static void main(String argv[]) throws Exception { + + final SAXParserFactory saxPf = SAXParserFactory.newInstance(); + final SAXParser saxParser = saxPf.newSAXParser(); + final XMLReader xmlReader = saxParser.getXMLReader(); + final ListTagNamesHandler handler = new ListTagNamesHandler(); + xmlReader.setContentHandler(handler); + xmlReader.setErrorHandler(new MyErrorHandler()); + xmlReader.parse("Input/Xml/Memo/message.xml"); + + System.out.print("List of elements: {"); + for (String elementName : handler.getTagNames()) { + System.out.print(elementName + " "); + } + System.out.println("}"); + } +} \ No newline at end of file diff --git a/ws/eclipse/Jdbc/src/main/java/sax/count/ListTagNamesHandler.java b/ws/eclipse/Jdbc/src/main/java/sax/count/ListTagNamesHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..cfb6bb92cda267b1700a278ecf399584711b4dd3 --- /dev/null +++ b/ws/eclipse/Jdbc/src/main/java/sax/count/ListTagNamesHandler.java @@ -0,0 +1,35 @@ +package sax.count; + +import java.util.SortedSet; +import java.util.TreeSet; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** Reading attributes from element events */ +public class ListTagNamesHandler extends DefaultHandler { + + // A SortedSet by definition does not contain any duplicates. + private SortedSet<String> elementNames = new TreeSet<>(); + + @Override + public void startDocument() throws SAXException { + elementNames.clear(); // May contain elements from a previous run. + } + + public void startElement(String namespaceUri, String localName, + String rawName, Attributes attrs) { + // In case the current element name has already been inserted + // this method call will be silently ignored. + elementNames.add(rawName); + } + + /** + * @return A sorted list of element names of he currently processed XML + * document without duplicates. + */ + public String[] getTagNames() { + return elementNames.toArray(new String[0]); + } +} \ No newline at end of file