📄 jaxpsax3.html
字号:
try { nl(); out.flush(); } catch (IOException e) { throw new SAXException("I/O error", e); }}</code><a name="wp64255"> </a>private void echoText()...<a name="wp64256"> </a></pre></div><a name="wp64257"> </a><p class="pBody">Here, you are echoing an XML declaration when the parser encounters the start of the document. Since you set up the <code class="cCode">OutputStreamWriter</code> using the UTF-8 encoding, you include that specification as part of the declaration.</p><hr><a name="wp64258"> </a><p class="pNote">Note: However, the IO classes don't understand the hyphenated encoding names, so you specified "UTF8" rather than "UTF-8".</p><hr><a name="wp64259"> </a><p class="pBody">At the end of the document, you simply put out a final newline and flush the output stream. Not much going on there. </p><a name="wp71046"> </a><h4 class="pHeading3">Element Events</h4><a name="wp71045"> </a><p class="pBody">Now for the interesting stuff. Add the code highlighted below to process the start-element and end-element events:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative"><code class="cCodeBold">public void startElement(String namespaceURI, String sName, // simple name String qName, // qualified name Attributes attrs)throws SAXException{ String eName = sName; // element name if ("".equals(eName)) eName = qName; // not namespaceAware emit("<"+eName); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { String aName = attrs.getLocalName(i); // Attr name if ("".equals(aName)) aName = attrs.getQName(i); emit(" "); emit(aName+"=\""+attrs.getValue(i)+"\""); } } emit(">");}</code><a name="wp67437"> </a><code class="cCodeBold">public void endElement(String namespaceURI, String sName, // simple name String qName // qualified name )throws SAXException{ String eName = sName; // element name if ("".equals(eName)) eName = qName; // not namespaceAware emit("<"+eName+">");}</code><a name="wp64261"> </a>private void emit(String s)...<a name="wp64263"> </a></pre></div><a name="wp64264"> </a><p class="pBody">With this code, you echoed the element tags, including any attributes defined in the start tag. Note that when the <code class="cCode">startElement</code>() method is invoked, the simple name ("local name") for elements and attributes could turn out to be the empty string, if namespace processing was not enabled. The code handles that case by using the qualified name whenever the simple name is the empty string.</p><a name="wp71050"> </a><h4 class="pHeading3">Character Events</h4><a name="wp64265"> </a><p class="pBody">To finish handling the content events, you need to handle the characters that the parser delivers to your application. </p><a name="wp71093"> </a><p class="pBody">Parsers are not required to return any particular number of characters at one time. A parser can return anything from a single character at a time up to several thousand, and still be standard-conforming implementation. So, if your application needs to process the characters it sees, it is wise to accumulate the characters in a buffer, and operate on them only when you are sure they have all been found.</p><a name="wp71154"> </a><p class="pBody">Add the line highlighted below to define the text buffer:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">public class Echo01 extends DefaultHandler{ <code class="cCodeBold">StringBuffer textBuffer;</code> public static void main(String argv[]) {<a name="wp71155"> </a>...<a name="wp71070"> </a></pre></div><a name="wp71208"> </a><p class="pBody">Then add the code highlighted below to accumulate the characters the parser delivers in the buffer:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">public void endElement(...)throws SAXException{ ...}<a name="wp71137"> </a><code class="cCodeBold">public void characters(char buf[], int offset, int len)throws SAXException{ String s = new String(buf, offset, len); if (textBuffer == null) { textBuffer = new StringBuffer(s); } else { textBuffer.append(s); }}</code><a name="wp71187"> </a>private void emit(String s)...<a name="wp64267"> </a></pre></div><a name="wp64268"> </a><p class="pBody">Next, add this method highlighted below to send the contents of the buffer to the output stream.</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">public void characters(char buf[], int offset, int len)throws SAXException{ ...}<a name="wp71278"> </a><code class="cCodeBold">private void echoText()throws SAXException{ if (textBuffer == null) return; String s = ""+textBuffer; emit(s); textBuffer = null;}</code><a name="wp71297"> </a>private void emit(String s)...<a name="wp71279"> </a></pre></div><a name="wp71267"> </a><p class="pBody">When this method is called twice in a row (which will happens at times, as we'll see next), the buffer will be null. So in that case, the method simply returns. When the buffer is non-null, however, it's contents are sent to the output stream.</p><a name="wp71276"> </a><p class="pBody">Finally, add the code highlighted below to echo the contents of the buffer whenever an element starts or ends:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">public void startElement(...)throws SAXException{ <code class="cCodeBold">echoText();</code> String eName = sName; // element name ...}<a name="wp71356"> </a>public void endElement(...)throws SAXException{ <code class="cCodeBold">echoText();</code> String eName = sName; // element name ...}<a name="wp71402"> </a></pre></div><a name="wp71266"> </a><p class="pBody">You're done accumulating text when an element ends, of course. So you echo it at that point, which clears the buffer before the next element starts.</p><a name="wp71419"> </a><p class="pBody">But you also want to echo the accumulated text when an element starts! That's necessary for document-style data, which can contain XML elements that are intermixed with text. For example, in this document fragment:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative"><code class="cCodeBold"><para></code>This paragraph contains <code class="cCodeBold"><bold></code>important<code class="cCodeBold"></bold></code> ideas.<code class="cCodeBold"></para></code><a name="wp71432"> </a></pre></div><a name="wp71433"> </a><p class="pBody">The initial text, "This paragraph contains" is terminated by the start of the <code class="cCode"><bold></code> element. The text, "important" is terminated by the end tag, <code class="cCode"></bold></code>, and the final text, "ideas.", is terminated by the end tag, <code class="cCode"></para></code>.</p><hr><a name="wp71462"> </a><p class="pNote">Note: Most of the time, though, the accumulated text will be echoed when an <code class="cCode">endElement()</code> event occurs. When a <code class="cCode">startElement()</code> event occurs after that, the buffer will be empty. The first line in the <code class="cCode">echoText()</code> method checks for that case, and simply returns.</p><hr><a name="wp71413"> </a><p class="pBody">Congratulations! At this point you have written a complete SAX parser application. The next step is to compile and run it.</p><hr><a name="wp64269"> </a><p class="pNote">Note: To be strictly accurate, the character handler should scan the buffer for ampersand characters ('<code class="cCode">&');</code>and left-angle bracket characters ('<') and replace them with the strings "<code class="cCode">&amp;</code>" or "<code class="cCode">&lt;</code>", as appropriate. You'll find out more about that kind of processing when we discuss entity references in <a href="JAXPSAX6.html#wp64737">Displaying Special Characters and CDATA</a>. </p><hr><a name="wp64274"> </a><h3 class="pHeading2">Compiling and Running the Program</h3><a name="wp96469"> </a><p class="pBody">In the J2EE release, the JAXP libraries are in the directory <code class="cVariable"><J2EE_HOME></code><code class="cCode">/share/lib/endorsed</code>. These are newer versions of the standard JAXP libraries that are part of the Java 2 platform.</p><a name="wp96471"> </a><p class="pBody">The J2EE Application Server automatically uses the newer libraries when a program runs. So you won't have to be concerned with where they reside when you deploy an application.</p><a name="wp95720"> </a><p class="pBody">And since the JAXP APIs are identical in both versions, you won't need to be concerned at compile time either. So compiling the program you created is as simple as issuing the command:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">javac Echo.java<a name="wp95842"> </a></pre></div><a name="wp95844"> </a><p class="pBody">But to run the program outside of the server container, you need to make sure that the <code class="cCode">java</code> runtime finds the newer versions of the JAXP libraries. That situation can occur, for example, when unit-testing parts of your application outside of the sever, as well as here, when running the XML tutorial examples.</p><a name="wp96907"> </a><p class="pBody">There are two ways to make sure that the program uses the latest version of the JAXP libraries:</p><div class="pSmartList1"><ul class="pSmartList1"><a name="wp96916"> </a><div class="pSmartList1"><li>Copy the <code class="cVariable"><J2EE_HOME></code><code class="cCode">/share/lib/endorsed diretory</code> directory to <<span style="font-style: italic">J2EE_HOME</span>>jdk/jre/lib/endorsed. You can then run the program with this command:</li></div><div class="pPreformattedRelative"><pre class="pPreformattedRelative"> <span style="font-style: normal"><</span><span style="font-style: italic">J2EE_HOME</span>>/jdk/bin/java Echo slideSample.xml<a name="wp96917"> </a><a name="wp96918"> </a><p class="pBodyRelative">The libraries will then be found in the endorsed standards directory, <<span style="font-style: italic">J2EE_HOME</span>>/jdk/jre/lib/endorsed.</p></pre></div><a name="wp96919"> </a><div class="pSmartList1"><li>Use the endorsed directories system property to specify the location of the libraries, by specifying this option on the <code class="cCode">java</code> command line: <code class="cCode">-</code><code class="cCode">D"java.endorsed.dirs=</code><code class="cVariable"><J2EE_HOME></code><code class="cCode">/share/lib/endorsed</code><code class="cCode">"</code></li></div></ul></div><hr><a name="wp96912"> </a><p class="pNote">Note: Since the JAXP <span style="font-style: italic">APIs</span> are already built into the Java 2 platform, they don't need to be specified at compile time. (In fact, the -D option is not even allowed at compile time, because endorsed standards are <span style="font-style: italic">required</span> to maintain consistent APIs.) However, when the JAXP factories instantiate an <span style="font-style: italic">implementation</span>, the endorsed directories mechanism is employed to make sure that the desired implementation is instantiated. </p><hr><a name="wp67478"> </a><h3 class="pHeading2">Checking the Output</h3><a name="wp64333"> </a><p class="pBody">Here is part of the program's output, showing some of its weird spacing:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative"><code class="cCode">...</code><slideshow title="Sample Slide Show" date="Date of publication" author="Yours Truly"> <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide> ...<a name="wp64334"> </a></pre></div><hr><a name="wp64336"> </a><p class="pNote">Note: The program's output is contained in <code class="cCode"><a href="../examples/jaxp/sax/samples/Echo01-01.txt" target="_blank">Echo01-01.txt</a></code>. (The browsable version is <code class="cCode"><a href="../examples/jaxp/sax/samples/Echo01-01.html" target="_blank">Echo01-01.html</a></code>.)</p><hr><a name="wp67558"> </a><p class="pBody">Looking at this output, a number of questions arise. Namely, where is the excess vertical whitespace coming from? And why is it that the elements are indented properly, when the code isn't doing it? We'll answer those questions in a moment. First, though, there are a few points to note about the output: </p><div class="pSmartList1"><ul class="pSmartList1"><a name="wp64337"> </a><div class="pSmartList1"><li>The comment defined at the top of the file </li></div><div class="pPreformattedRelative"><pre class="pPreformattedRelative"> <!-- A SAMPLE set of slides --><a name="wp64338"> </a></pre></div></ul></div><a name="wp64339"> </a><p class="pDefinition">does not appear in the listing. Comments are ignored, unless you implement a <code class="cCode">LexicalHandler</code>. You'll see more about that later on in this tutorial.</p><div class="pSmartList1"><ul class="pSmartList1"><a name="wp64340"> </a><div class="pSmartList1"><li>Element attributes are listed all together on a single line. If your window isn't really wide, you won't see them all.</li></div><a name="wp64341"> </a><div class="pSmartList1"><li>The single-tag empty element you defined (<code class="cCode"><item/></code>) is treated exactly the same as a two-tag <span style="font-style: italic">empty element</span> (<code class="cCode"><item></item></code>). It is, for all intents and purposes, identical. (It's just easier to type and consumes less space.) </li></div></ul></div><a name="wp64343"> </a><h3 class="pHeading2">Identifying the Events</h3><a name="wp64344"> </a><p class="pBody">This version of the echo program might be useful for displaying an XML file, but it's not telling you much about what's going on in the parser. The next step is to modify the program so that you see where the spaces and vertical lines are coming from.</p><hr><a name="wp64345"> </a><p class="pNote">Note: The code discussed in this section is in <code class="cCode"><a href="../examples/jaxp/sax/samples/Echo02.java" target="_blank">Echo02.java</a></code>. The output it produces is shown in <code class="cCode"><a href="../examples/jaxp/sax/samples/Echo02-01.txt" target="_blank">Echo02-01.txt</a></code>. (The browsable version is <code class="cCode"><a href="../examples/jaxp/sax/samples/Echo02-01.html" target="_blank">Echo02-01.html</a></code>)</p><hr><a name="wp64346"> </a><p class="pBody"> Make the changes highlighted below to identify the events as they occur:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">public void startDocument()throws SAXException{ <code class="cCodeBold">nl(); nl();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -