📄 4_tree.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><!--NewPage--><html><head><title>JTree from DOM</title><style type="text/css"><!----></style></head><body BGCOLOR="#ffffff"><table width="100%"> <tr> <td align=left> <ahref="3_display.html"><img src="../images/PreviousArrow.gif" width=26 height=26 align=bottom border=0 alt="Previous | "></a><a href="5_create.html"><img src="../images/NextArrow.gif" width=26 height=26 align=bottom border=0 alt="Next | "></a><a href="../alphaIndex.html"><img src="../images/xml_IDX.gif" width=26 height=26 align=bottom border=0 alt="Index | "></a><a href="../TOC.html"><imgsrc="../images/xml_TOC.gif" width=26 height=26 align=bottom border=0 alt="TOC | "></a><a href="../index.html"><imgsrc="../images/xml_Top.gif" width=26 height=26 align=bottom border=0 alt="Top | "></a> </td> <td align=right><strong><em><a href="index.html">Top</a></em></strong> <a href="../TOC.html#intro"><strong><em>Contents</em></strong></a> <a href="../alphaIndex.html"><strong><em>Index</em></strong></a> <a href="../glossary.html"><strong><em>Glossary</em></strong></a> </td> </tr></table><p> <center> <IMG SRC="../images/shoeline2.gif" ALIGN="BOTTOM" BORDER="0" WIDTH="202" HEIGHT="25" NATURALSIZEFLAG="3"> <IMG SRC="../images/shoeline2.gif" ALIGN="BOTTOM" BORDER="0" WIDTH="202" HEIGHT="25" NATURALSIZEFLAG="3"> </center><blockquote> <blockquote> <hr size=4> </blockquote></blockquote><p> <h2> 4. Constructing a User-Friendly JTree from a DOM</h2><table width="40%" border="1" align="right"> <tr> <td> <div align="center"><b><i>Link Summary</i></b></div> </td> </tr> <tr> <td> <dl> <dt><b><i>Local Links</i></b></dt> </dl> <ul> <li><a href="../sax/5d_dtd.html">Referencing Binary Entities</a> </li> <li><a href="../sax/9_notatn.html">Using the DTDHandler and EntityResolver</a></li> </ul> <dl> <dt><b><i>Exercise Links</i></b></dt> </dl> <ul> <li><a href="work/DomEcho03.java"><code>DomEcho03.java</code></a></li> <li><a href="work/DomEcho04.java"><code>DomEcho04.java</code></a></li> <li><a href="samples/slideSample01.xml"><code>slideSample01.xml</code></a></li> <li><a href="samples/slideSample01.xml"><code>slideSample10.xml</code></a></li> </ul> <dl> <dt><b><i>External Links</i></b></dt> </dl> <ul> <li><a href="http://java.sun.com/products/jfc/tsc/articles/jtree/index.html">Understanding the TreeModel</a></li> </ul> <p><b><i>Glossary Terms</i></b></p> <dl> <dd><a href="../glossary.html#wellFormed">well-formed</a><br> </dd> </dl> </td> </tr></table><p>Now that you know what a DOM looks like internally, you'll be better prepared to modify a DOM or construct one from scratch . Before going on to that, though, this section presents some modifications to the JTreeModel that let you produce a more user-friendly version of the JTree suitable for use in a GUI. <h3><a name="compressing"></a>Compressing the Tree View</h3><p>Displaying the DOM in tree form is all very well for experimenting and to learn how a DOM works. But it's not the kind of "friendly" display that most users want to see in a JTree. However, it turns out that very few modifications are needed to turn the TreeModel adapter into something that <i>will</i> present a user-friendly display. In this section, you'll make those modifications. <blockquote> <p><b>Note:</b> <br> The code discussed in this section is in <a href="work/DomEcho03.java"><code>DomEcho03.java</code></a>. The file it operates on is <a href="samples/slideSample01.xml"><code>slideSample01.xml</code></a>. </p></blockquote><h4><a name="selectable"></a>Make the Operation Selectable</h4><p>When you modify the adapter, you're going to <i>compress</i> the view of the DOM, eliminating all but the nodes you really want to display. Start by defining a boolean variable that controls whether you want the compressed or uncompressed view of the DOM:</p><blockquote> <p></blockquote><blockquote> <p></p> <pre>public class DomEcho extends JPanel{ static Document document; <new><b>boolean compress = true;</b></new> static final int windowHeight = 460; ...</pre> <new></new> </blockquote><h4><a name="identify"></a>Identify "Tree" Nodes</h4><p>The next step is to identify the nodes you want to show up in the tree. To do that, go to the area where you defined the names of all the element types (in the <code>typeName</code> array), and add the code highlighted below:</p><blockquote> <p></p> <pre>public class DomEcho extends JPanel{ ... public static void makeFrame() { ... } // An array of names for DOM node-types static String[] typeName = { ... }; <new><b>final int ELEMENT_TYPE = 1;</b></new> <new><b>// The list of elements to display in the tree</b></new> <new><b>static String[] treeElementNames = {</b></new> <new><b>"slideshow",</b></new> <new><b>"slide",</b></new> <new><b>"title", // For slideshow #1</b></new> <new><b>"slide-title", // For slideshow #10</b></new> <new><b>"item",</b></new> <new><b>};</b></new> <new><b>boolean treeElement(String elementName) {</b></new> <new><b>for (int i=0; i<treeElementNames.length; i++) {</b></new> <new><b>if ( elementName.equals(treeElementNames[i]) ) return true;</b></new> <new><b>}</b></new> <new><b>return false;</b></new> <new><b>}</b></new> </pre> </blockquote><p>With this code, you set up a constant you can use to identify the <tt>ELEMENT</tt> node type, declared the names of the elements you want in the tree, and created a method tells whether or not a given element name is a "tree element". Since slideSample01.xml has <tt>title</tt> elements and slideSample10.xml has <tt>slide-title</tt> elements, you set up the contents of this arrays so it would work with either data file. <blockquote><b>Note:</b><br> The mechanism you are creating here depends on the fact that <i>structure</i> nodes like <tt>slideshow</tt> and <tt>slide</tt> never contain text, while text usually does appear in <i>content</i> nodes like <tt>item</tt>. Although those "content" nodes may contain subelements in slideShow10.xml, the DTD constrains those subelements to be XHTML nodes. Because they are XHTML nodes (an XML version of HTML that is constrained to be <a href="../glossary.html#wellFormed">well-formed</a>), the entire substructure under an <tt>item</tt> node can be combined into a single string and displayed in the <tt>htmlPane</tt> that makes up the other half of the application window. In the second part of this section, you'll do that concatenation, displaying the text and XHTML as content in the <tt>htmlPane</tt>.</blockquote><h4><a name="visibility"></a>Control Node Visibility</h4><p>The next step is to modify the AdapterNode's <tt>childCount</tt> function so that it only counts "tree element" nodes -- nodes which are designated as displayable in the JTree. Make the modifications highlighted below to do that: </p><blockquote> <p></p> <p></p> <pre>public class DomEcho extends JPanel{ ... public class AdapterNode { ... public AdapterNode child(int searchIndex) { ... } public int childCount() { <new><b>if (!compress) {</b></new> <new><b>// Indent this</b></new> return domNode.getChildNodes().getLength(); <new><b>} </b></new> <new><b>int count = 0;</b></new> <new><b>for (int i=0; i<domNode.getChildNodes().getLength(); i++) {</b></new> <new><b>org.w3c.dom.Node node = domNode.getChildNodes().item(i); </b></new> <new><b>if (node.getNodeType() == ELEMENT_TYPE</b></new> <new><b>&& treeElement( node.getNodeName() )) </b></new> <new><b>{</b></new> <new><b>++count;</b></new> <new><b>}</b></new> <new><b>}</b></new> <new><b>return count;</b></new> } } // AdapterNode</pre></blockquote><p>The only tricky part about this code is checking to make sure the node is an element node before comparing the node. The DocType node makes that necessary, because it has the same name, "slideshow", as the <tt>slideshow</tt> element.</p><h4><a name="access"></a>Control Child Access</h4><p>Finally, you need to modify the AdapterNode's <tt>child</tt> function to return the Nth item from the list of displayable nodes, rather than the Nth item from all nodes in the list. Add the code highlighted below to do that:</p><p> <blockquote> <p></p> <pre>public class DomEcho extends JPanel{ ... public class AdapterNode { ... public int index(AdapterNode child) { ... } public AdapterNode child(int searchIndex) { //Note: JTree index is zero-based. org.w3c.dom.Node node = domNode.getChildNodes().item(searchIndex); <new><b>if (compress) {</b></new> <new><b>// Return Nth displayable node</b></new> <new><b>int elementNodeIndex = 0;</b></new> <new><b>for (int i=0; i<domNode.getChildNodes().getLength(); i++) {</b></new> <new><b>node = domNode.getChildNodes().item(i);</b></new> <new><b>if (node.getNodeType() == ELEMENT_TYPE </b></new> <new><b>&& treeElement( node.getNodeName() )</b></new> <new><b>&& elementNodeIndex++ == searchIndex) {</b></new> <new><b>break; </b></new> <new><b>}</b></new> <new><b>}</b></new> <new><b>}</b></new> return new AdapterNode(node); } // child } // AdapterNode</pre></blockquote><p>There's nothing special going on here. It's a slightly modified version the same logic you used when returning the child count.</p><h4><a name="results"></a>Check the Results</h4><p>When you compile and run this version of the app on <a href="samples/slideSample01.xml"><code>slideSample01.xml</code></a>, and then expand the nodes in the tree, you see the results shown in Figure 1. The only nodes remaining in the tree are the high-level "structure" nodes. </p><blockquote> <p><img src="images/p301a.gif" width="640" height="440"><br> <i><b>Figure 1: Tree View with a Collapsed Hierarchy</b></i></p></blockquote><h4><a name="extra1"></a>Extra Credit</h4><p>The way the app stands now, the information that tells the app how to compress the tree for display is "hard coded". Here are some ways you could consider extending the app:</p><dl> <dl> <dt><new><b>Use a Command-Line Argument</b></new></dt> <dd><new>Whether you compress or don't compress the tree could be determined by a command line argument, rather than being a hard-coded boolean variable. On the other hand, the list</new><new> the list of elements that goes into the tree is still hard coded, so maybe that option doesn't make much sense, unless..</new><new>.</new><new></new></dd> <dt> </dt> <dt><b>Read the treeElement list from a file</b></dt> <dd>If you read the list of elements to include in the tree from an external file, that would make the whole app command driven. That would be good. But wouldn't it be really nice to derive that information from the DTD or schema, instead? So you might want to consider...</dd> <dt> </dt> <dt><new><b>Automatically Build the List </b></new></dt> <dd><new> Watch out, though! As things stand right now, there are no standard DTD parsers! If you use a DTD, then, you'll need to write your parser to make sense out of its somewhat arcane syntax. You'll probably have better luck if you use a <a href="../glossary.html#schema">schema</a>, instead of a DTD. The nice thing about schemas is that use XML syntax, so you can use an XML parser to read the schema the same way you use any other file.<br> </new><br> As you analyze the schema, note that the JTree-displayable <i>structure</i> nodes are those that have no text, while the <i>content</i> nodes may contain text and, optionally, XHTML subnodes. That distinction works for this example, and will likely work for a large body of real-world applications<new>. It's pretty easy to construct cases that will create a problem, though, so you'll have to be on the lookout for schema/DTD specifications that embed non-XHTML elements in text-capable nodes, and take the appropriate action.</new></dd> </dl></dl><h3><a name="selections"></a>Acting on Tree Selections </h3><p>Now that the tree is being displayed properly, the next step is to concatenate the subtrees under selected nodes to display them in the <tt>htmlPane</tt>. While you're at it, you'll use the concatenated text to put node-identifying information back in the JTree. </p><blockquote> <p><b>Note:</b> <br> The code discussed in this section is in <a href="work/DomEcho04.java"><code>DomEcho04.java</code></a>.</p></blockquote><h4><a name="types"></a>Identify Node Types</h4><p>When you concatenate the sub nodes under an element, the processing you do is going to depend on the type of node. So the first thing to is to define constants for the remaining node types. Add the code highlighted below to do that:</p><blockquote> <p></p> <pre>public class DomEcho extends JPanel{ ... // An array of names for DOM node-types static String[] typeName = { ... }; static final int ELEMENT_TYPE = 1; <new><b>static final int ATTR_TYPE = 2;</b></new> <new><b>static final int TEXT_TYPE = 3;</b></new> <new><b>static final int CDATA_TYPE = 4;</b></new> <new><b>static final int ENTITYREF_TYPE = 5;</b></new> <new><b>static final int ENTITY_TYPE = 6;</b></new> <new><b>static final int PROCINSTR_TYPE = 7;</b></new> <new><b>static final int COMMENT_TYPE = 8;</b></new> <new><b>static final int DOCUMENT_TYPE = 9;</b></new> <new><b>static final int DOCTYPE_TYPE = 10;</b></new> <new><b>static final int DOCFRAG_TYPE = 11;</b></new> <new><b>static final int NOTATION_TYPE = 12;</b></new> </pre></blockquote><h4><a name="subnodes"></a>Concatenate Subnodes to Define Element Content</h4><p>Next, you need to define add the method that concatenates the text and subnodes for an element and returns it as the element's "content". To define
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -