﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-I have a dream-随笔分类-Java Language</title><link>http://www.blogjava.net/cipher/category/6001.html</link><description>Java&amp;computer science</description><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 19:21:32 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 19:21:32 GMT</pubDate><ttl>60</ttl><item><title>使用Java Swing 创建一个XML编辑器(ZZ from Matrix)</title><link>http://www.blogjava.net/cipher/archive/2005/12/19/24618.html</link><dc:creator>I have a dream</dc:creator><author>I have a dream</author><pubDate>Mon, 19 Dec 2005 04:54:00 GMT</pubDate><guid>http://www.blogjava.net/cipher/archive/2005/12/19/24618.html</guid><wfw:comment>http://www.blogjava.net/cipher/comments/24618.html</wfw:comment><comments>http://www.blogjava.net/cipher/archive/2005/12/19/24618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/cipher/comments/commentRss/24618.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/cipher/services/trackbacks/24618.html</trackback:ping><description><![CDATA[<DIV id=title>
<H2>使用Java Swing 创建一个XML编辑器</H2><A href="http://www.matrix.org.cn/user.shtml;jsessionid=EF99AFD9A148B40782BB3CECDB6C27BC?userid=2">chris</A> 发表于2003-07-17 评价:5/1 评论数:0 点击数:3226 [<A href="http://www.matrix.org.cn/favorite.shtml;jsessionid=EF99AFD9A148B40782BB3CECDB6C27BC?type=article&amp;title=使用Java Swing 创建一个XML编辑器&amp;url=http://www.matrix.org.cn/articleView.shtml?id=392">收藏</A>] </DIV>
<DIV id=divnormal>
<DIV id=articleview_centerad></DIV>
<DIV id=articleview_summary>摘要：<BR><BR><BR><BR>本文Matrix永久镜像：<A href="http://www.matrix.org.cn/resource/article/0/392.html">http://www.matrix.org.cn/resource/article/0/392.html</A> <BR>说明：本文可能由Matrix原创，也可能由Matrix的会员整理，或者由<BR>Matrix的Crawler在全球知名Java或者其他技术相关站点抓取并永久<BR>保留镜像，Matrix会保留所有原来的出处URL，并在显著地方作出说明，<BR>如果你发觉出处URL有误，请联系Matrix改正.<BR></DIV></DIV>
<DIV id=divarticlecontent>出自：yesky<BR><BR>我想您一定对XML有所了解，说不定您现在还跃跃欲试想写一段XML文本呢，可是现在能找到的跨平台的、免费的XML编辑器太少了。所以在本文中，我想介绍一下或者说带您一步一步的开发一个简单的XML编辑器，当然我们要用到一些最常见的Java 2 Swing组件，不过这些都是免费的，有些是JDK中的，有些是可以从网上下载的。我想通过本文，你就可以创建一个属于你自己的XML编辑器。<BR><BR>　　先让我介绍一下本文辑写的思路。首先我想简要的讨论一下XML和为什么树型结构比较适合用来显示XML，然后我们来看一看JAXP API如何建立所需要的XML类的环境；然后我们将了解用来显示一个图形树的JTree Swing组件；最后，我们将创建一个继承JTree组件的可以重复使用的类，可以用来分析一个XML文档，并把数据显示在一个Jtree中。<BR><BR>　　说到XML(eXtensible Markup Languge)，人们往往把它当成是一种新的用于Web浏览器中的标记语言，就象HTML或CSS一样。其实，XML是一种数据表示语言，它允许你使用一种非常有效的方法来描述你的数据。XML能够使你定义诸如“these three words constitutes a heading”这样的语句。XML允许你声明任何类型的数据，而不是用来把这些数据显示在网页中。<BR><BR>　　请看一看下面的XML实例：<BR><BR>＜article＞<BR>＜header＞<BR>＜title＞ 使用Java Swing 创建一个XML编辑器<BR>＜subtitle＞ 第一部分＜/subtitle＞<BR>＜/title＞<BR>＜author＞ Wayne ＜/author＞<BR>＜header＞<BR>＜content＞ 这是正文＜/content＞<BR>＜/article＞<BR><BR><BR>　　请注意，这些元素和标准的HTML语句是不同的，但是它们看上去比较象HTML，这是因为XML和HTML都是来源于SGML语言。不同的是HTML有预定义的标签集，而XML的语法则有许多灵活性，它允许你使用表意的标记如＜author＞来括在数据两边。你还要注意，所有的元素都从属于根元素（上例中为＜article＞），有些元素则还有自己的子元素，如＜subtitle＞就是＜title＞的子元素。这样的数据组织方式有三个好处：数据能够更加表意，数据更加易维护而且数据更加容易作为一个树的结构表现出来，这就是我们为什么使用JTree对象来显示XML数据的原因。如果你想对XML有更深的了解，请参阅天极网上的相关教程。<BR><BR>　　JAXP是一个用于处理XML的Java API，它能够使应用程序分析并且转化XML文档,它的功能有点象JDBC API,都是把函数功能抽象成一个个方法。你可以去Apache网站找到最新的Xerces分析器，其中含有最新的JAXP，下载下来以后把它放在你的类目录中。<BR><BR>下面让我们看一下如何使用JTree Swing组件。<BR><BR>　　我们都知道，在自然界中，一棵树通常都有一个非常粗的树干，树干上有许多树枝分叉。每个树杈和树杈之间都有一定的联系，因为它们都有同一个来源：树干。这种继承的关系并不只在树枝中有，人类谱系也遵循相同的规律。从父母，到子女再到子女的子女，就这样直到数不清为止。同样，在数据存储中，树的概念也是一种使用同人类家谱树一样方法储存数据的方法。树的每一个树杈称为一个节点，每个有子节点的节点称为父节点，所有的子节点的公共的父节点被称为根节点。一个JTree组件就是一个简单的树数据结构的可视化表现形式。<BR><BR>　　几乎所有的XML编辑器都包括一个可视化的树结构，能让你编辑XML文档中的元素。我们马上就会构建一个编辑器，不过在此之前，先让我们再了解一下JTree组件。一个节点在一棵树的某个位置储存数据，为了存储数据，必须知道任何一个父节点和它们的子节点。javax.swing.tree包定义了一些非常有用的接口，提供了一种通用的方法构建和操作一个树结构。<BR><BR>　　TreeNode方法，用于访问树的节点的信息<BR><BR>　　MutableTreeNode方法 用在一个可变的树上（能够添加或删除子节点）<BR><BR>　　TreeModel方法 用于创建和管理与树有关的数据模型。<BR><BR>　　接下来，我们将创建一个继承JTree的类，提供分析XML文档和用可视化JTree组件把节点显示出来的功能。<BR><BR>　　创建XTree组件<BR><BR>　　XTree类由一个构造函数和三个方法组成，为了简单起见我们的组件只能构建一个Xtree，在树创建好之后不能进行处理它的节点。下面让我们来看一个这个类。<BR><BR>　　域：<BR><BR>　　private DefaultMutableTreeNode treeNode 这个成员变量储存TreeNode对象用于存储JTree的模型。　<BR><BR>　　DefaultMutableTreeNode类是在javax.swing.tree中被定义的，默认提供了MutableTreeNode接口的一个实现。<BR><BR>　　private DocumentBuilderFactory dbf<BR><BR>　　private DocumentBuilder db<BR><BR>　　private Document doc 这三个成员变量是JAXP的一部分，用来分析XML文本并转化成DOM（Document Object Model) 对象。<BR><BR>　　构造函数<BR><BR>　　public XTree( String text )<BR><BR>　　这个构造函数通过使用传送到构造器中的XML文本创建一个XTree对象。在初始化一些与JTree超类和DOM分析对象有关的基本显示属性后，构造函数生成一个TreeModel 对象用来创建一个实际可视的树。通过把DOM对象传送到createTreeNode()方法来创建一个根节点，createTreeNode()方法返回一个DefaultMutableTreeNode类型的对象。这个对象然后被用来创建树的TreeModel。<BR><BR>　　方法<BR><BR>　　　private DefaultMutableTreeNode createTreeNode( Node root )<BR><BR>　　这个方法采用一个DOM 节点，然后在子节点中递归直到所有的接点都被添加到DefaultMutableTreeNode中。这是一个递归方法，为了找到根节点下的每一个子节点，它每次都要调用自己。JTree然后就可以使用DefaultMutableTreeNode对象了，因为它已经是树型了。 <BR><BR>　　　private String getNodeType( Node node )<BR><BR>　　这个方法，被createTreeNode()用来联系一个字符串和某一种类型的节点。 <BR><BR>　　　private Node parseXml()<BR><BR>　　这个方法，用来分析XML文本字符串，它返回Node类型的对象，能够被传送到createTreeNode()方法中。 <BR>下面我给出了java代码，供大家分析研究。 <BR><BR>// 到入W3C的DOM 类<BR>import org.w3c.dom.*;<BR>// JAXP的用于DOM I/O的类<BR>import javax.xml.parsers.*;<BR>// 标准Java类<BR>import javax.swing.*;<BR>import javax.swing.tree.*;<BR>import javax.swing.event.*;<BR>import java.awt.*;<BR>import java.awt.event.*;<BR>import java.io.*;<BR>public class XTree extends JTree<BR>{<BR>/**<BR>* 这个成员变量储存TreeNode对象用于存储JTree的模型。<BR>*DefaultMutableTreeNode类是在javax.swing.tree中被定义的<BR>*默认提供了MutableTreeNode接口的一个实现。<BR>*/<BR>private DefaultMutableTreeNode treeNode;<BR>/**<BR>* 这三个成员变量是JAXP的一部分，用来分析XML文本并转化成DOM（Document Object Model) 对象。<BR>*/<BR>private DocumentBuilderFactory dbf;<BR>private DocumentBuilder db;<BR>private Document doc; <BR><BR>　/**<BR>　* 这个构造函数通过使用传送到构造器中的XML文本创建一个XTree对象<BR><BR>　* @参数 text是一个XML格式的XML文本<BR><BR>　* @异常 ParserConfigurationException 如果构造函数非正常的设置分析器，就会抛出异常<BR><BR>　*/<BR><BR>public XTree( String text ) throws ParserConfigurationException<BR>{<BR>super();<BR><BR>// 设置Tree渲染的基本属性<BR>getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );<BR>setShowsRootHandles( true );<BR>setEditable( false ); // 允许树可以编辑<BR><BR>// 通过初始化对象的DOM来分析对象<BR>dbf = DocumentBuilderFactory.newInstance();<BR>dbf.setValidating( false );<BR>db = dbf.newDocumentBuilder();<BR><BR>// 采用DOM根节点并且把它转化成JTree的树模型<BR>treeNode = createTreeNode( parseXml( text ) );<BR>setModel( new DefaultTreeModel( treeNode ) );<BR>} file://中止XTree()<BR><BR><BR>　　/**<BR><BR>　　* 这个方法采用一个DOM 节点，然后在子节点中递归直到所有的接点都被添加到DefaultMutableTreeNode中。<BR><BR>　　* 这是一个递归方法，为了找到根节点下的每一个子节点，它每次都要调用自己。<BR><BR>　　* JTree然后就可以使用DefaultMutableTreeNode对象了，因为它已经是树型了。<BR><BR>　　*<BR><BR>　　* @参数 root org.w3c.Node.Node<BR><BR>　　*<BR><BR>　　* @返回值 返回一个基于根节点DefaultMutableTreeNode对象<BR><BR>　　*/<BR><BR>private DefaultMutableTreeNode createTreeNode( Node root )<BR>{<BR>DefaultMutableTreeNode treeNode = null;<BR>String type, name, value;<BR>NamedNodeMap attribs;<BR>Node attribNode;<BR><BR>// 从根节点中取得数据<BR>type = getNodeType( root );<BR>name = root.getNodeName();<BR>value = root.getNodeValue();<BR><BR>treeNode = new DefaultMutableTreeNode( root.getNodeType() == Node.TEXT_NODE ? value : name );<BR><BR>// 显示属性<BR>attribs = root.getAttributes();<BR>if( attribs != null )<BR>{<BR>for( int i = 0; i ＜ attribs.getLength(); i++ )<BR>{<BR>attribNode = attribs.item(i);<BR>name = attribNode.getNodeName().trim();<BR>value = attribNode.getNodeValue().trim();<BR><BR>if ( value != null )<BR>{<BR>if ( value.length() ＞ 0 )<BR>{<BR>treeNode.add( new DefaultMutableTreeNode( "[Attribute] --＞ " + name + "=\"" + value + "\"" ) );<BR>} file://end if ( value.length() ＞ 0 )<BR>} file://end if ( value != null )<BR>} file://end for( int i = 0; i ＜ attribs.getLength(); i++ )<BR>} file://end if( attribs != null )<BR><BR>// 如果存在子节点，递归<BR>if( root.hasChildNodes() )<BR>{<BR>NodeList children;<BR>int numChildren;<BR>Node node;<BR>String data;<BR><BR>children = root.getChildNodes();<BR>// 如果子节点非空的话，只递归<BR>if( children != null )<BR>{<BR>numChildren = children.getLength();<BR><BR>for (int i=0; i ＜ numChildren; i++)<BR>{<BR>node = children.item(i);<BR>if( node != null )<BR>{<BR>if( node.getNodeType() == Node.ELEMENT_NODE )<BR>{<BR>treeNode.add( createTreeNode(node) );<BR>} file://end if( node.getNodeType() == Node.ELEMENT_NODE )<BR><BR>data = node.getNodeValue();<BR><BR>if( data != null )<BR>{<BR>data = data.trim();<BR>if ( !data.equals("\n") &amp;&amp; !data.equals("\r\n") &amp;&amp; data.length() ＞ 0 )<BR>{<BR>treeNode.add(createTreeNode(node));<BR>} file://end if ( !data.equals("\n") &amp;&amp; !data.equals("\r\n") &amp;&amp; data.length() ＞ 0 )<BR>} file://end if( data != null )<BR>} file://end if( node != null )<BR>} file://end for (int i=0; i ＜ numChildren; i++)<BR>} file://end if( children != null )<BR>} file://end if( root.hasChildNodes() )<BR>return treeNode;<BR>} file://end createTreeNode( Node root )<BR><BR><BR>　　/**<BR><BR>　　* 这个方法，被createTreeNode()用来联系一个字符串和某一种类型的节点。<BR><BR>　　*<BR><BR>　　* @参数 node org.w3c.Node.Node<BR><BR>　　*<BR><BR>　　* @返回值 返回显示节点类的字符串<BR><BR>　　*/<BR><BR>private String getNodeType( Node node )<BR>{<BR>String type;<BR><BR>switch( node.getNodeType() )<BR>{<BR>case Node.ELEMENT_NODE:<BR>{<BR>type = "Element";<BR>break;<BR>}<BR>case Node.ATTRIBUTE_NODE:<BR>{<BR>type = "Attribute";<BR>break;<BR>}<BR>case Node.TEXT_NODE:<BR>{<BR>type = "Text";<BR>break;<BR>}<BR>case Node.CDATA_SECTION_NODE:<BR>{<BR>type = "CData section";<BR>break;<BR>}<BR>case Node.ENTITY_REFERENCE_NODE:<BR>{<BR>type = "Entity reference";<BR>break;<BR>}<BR>case Node.ENTITY_NODE:<BR>{<BR>type = "Entity";<BR>break;<BR>}<BR>case Node.PROCESSING_INSTRUCTION_NODE:<BR>{<BR>type = "Processing instruction";<BR>break;<BR>}<BR>case Node.COMMENT_NODE:<BR>{<BR>type = "Comment";<BR>break;<BR>}<BR>case Node.DOCUMENT_NODE:<BR>{<BR>type = "Document";<BR>break;<BR>}<BR>case Node.DOCUMENT_TYPE_NODE:<BR>{<BR>type = "Document type";<BR>break;<BR>}<BR>case Node.DOCUMENT_FRAGMENT_NODE:<BR>{<BR>type = "Document fragment";<BR>break;<BR>}<BR>case Node.NOTATION_NODE:<BR>{<BR>type = "Notation";<BR>break;<BR>}<BR>default:<BR>{<BR>type = "???";<BR>break;<BR>}<BR>}// 结束 switch( node.getNodeType() )<BR>return type;<BR>} file://结束 getNodeType()<BR><BR><BR>　　/**<BR><BR>　　* 这个方法，用来分析XML文本字符串，它返回Node类型的对象，能够被传送到createTreeNode()方法中。<BR><BR>　　*<BR><BR>　　* @参数 text 一个显示XML文档的字符串<BR><BR>　　* @返回值 返回一个org.w3c.Node.Node对象<BR><BR>　　*/<BR><BR>private Node parseXml( String text )<BR>{<BR>ByteArrayInputStream byteStream;<BR><BR>byteStream = new ByteArrayInputStream( text.getBytes() );<BR><BR>try<BR>{<BR>doc = db.parse( byteStream );<BR>}<BR>catch ( Exception e )<BR>{<BR>e.printStackTrace();<BR>System.exit(0);<BR>}<BR>return ( Node )doc.getDocumentElement();<BR>} file://结束 parseXml()<BR><BR>} file://结束 class XTree<BR><BR><BR><BR><BR><BR>　　代码2 XTreeTester.java<BR><BR>import javax.xml.parsers.*;<BR><BR>// GUI类<BR>import javax.swing.*;<BR>import java.awt.*;<BR>import java.awt.event.*;<BR><BR>file://标准 Java类<BR>import java.io.*;<BR><BR><BR>public class XTreeTester extends JFrame<BR>{<BR>// XTree对象，用来在JTree中显示XML<BR>private XTree xTree;<BR>// JScrollPane是JTree的容器<BR>private JScrollPane jScroll;<BR>private WindowListener winClosing;<BR><BR>// 设置框架的宽和高<BR>private static final int FRAME_WIDTH = 400;<BR>private static final int FRAME_HEIGHT = 300;<BR><BR><BR>　　/*<BR><BR>　　* 构造器构造一个框架包含JScrollPane,<BR><BR>　　* 把一个基于XML字符串的XTree对象传到构造函数中<BR><BR>　　*/<BR><BR>public XTreeTester( String title, String xml ) throws ParserConfigurationException<BR>{<BR>super( title );<BR><BR>Toolkit toolkit;<BR>Dimension dim, minimumSize;<BR>int screenHeight, screenWidth;<BR><BR>// 初始化基本的布局属性<BR>setBackground( Color.lightGray );<BR>getContentPane().setLayout( new BorderLayout() );<BR>toolkit = Toolkit.getDefaultToolkit();<BR>dim = toolkit.getScreenSize();<BR>screenHeight = dim.height;<BR>screenWidth = dim.width;<BR>setBounds( (screenWidth-FRAME_WIDTH)/2, (screenHeight-FRAME_HEIGHT)/2, FRAME_WIDTH, FRAME_HEIGHT );<BR><BR>// 构建XTree对象<BR>xTree = new XTree( xml );<BR><BR>file://把XTree封装到JScroll中，以便在JFrame可以使它在屏幕中上下滚动.<BR>jScroll = new JScrollPane();<BR>jScroll.getViewport().add( xTree );<BR><BR>// 添加滚动条到框架中<BR>getContentPane().add( jScroll, BorderLayout.CENTER );<BR>validate();<BR>setVisible(true);<BR>// 添加WindowListener用来关闭窗口<BR>winClosing = new WindowAdapter()<BR>{<BR>public void windowClosing(WindowEvent e)<BR>{<BR>exit();<BR>}<BR>};<BR>addWindowListener(winClosing);<BR>}<BR><BR><BR>　　// 程序从这里开始执行。必须把一个以xml为扩展名的XML文件传送到这个方法中，其格式为java XTreeTester yourxmlfilename.xml<BR><BR>public static void main( String[] args )<BR>{<BR>String fileName = "";<BR>BufferedReader reader;<BR>String line;<BR>StringBuffer xmlText;<BR>XTreeTester xTreeTester;<BR><BR>// 创建一个基于特定XML文件的文档对象<BR>try<BR>{<BR>if( args.length ＞ 0 )<BR>{<BR>fileName = args[0];<BR><BR>if ( fileName.substring( fileName.indexOf( '.' ) ).equals( ".xml" ) )<BR>{<BR>reader = new BufferedReader( new FileReader( fileName ) );<BR>xmlText = new StringBuffer();<BR><BR>while ( ( line = reader.readLine() ) != null )<BR>{<BR>xmlText.append( line );<BR>}<BR><BR>// 分析完文档对象后将重写文件<BR>reader.close();<BR><BR>// 构造 GUI 组件<BR>xTreeTester = new XTreeTester( "XTree 测试", xmlText.toString() );<BR>}<BR>else<BR>{<BR>help();<BR>}<BR>}<BR>else<BR>{<BR>help();<BR>}<BR>}<BR>catch( FileNotFoundException fnfEx )<BR>{<BR>System.out.println( "没有发现"+ fileName + "文件。" );<BR>exit();<BR>}<BR>catch( Exception ex )<BR>{<BR>ex.printStackTrace();<BR>exit();<BR>}<BR>}<BR><BR><BR>　　file://帮助信息<BR><BR>private static void help()<BR>{<BR>System.out.println( "\n使用方法：java XTreeTester yourxmlfilename.xml" );<BR>System.exit(0);<BR>}<BR><BR>// 退出<BR>private static void exit()<BR>{<BR>System.out.println( "\n谢谢使用 XTree" );<BR>System.exit(0);<BR>} <BR><BR>} <BR><BR></DIV><img src ="http://www.blogjava.net/cipher/aggbug/24618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/cipher/" target="_blank">I have a dream</a> 2005-12-19 12:54 <a href="http://www.blogjava.net/cipher/archive/2005/12/19/24618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>