/Users/lyon/j4p/src/classUtils/pack/beans/xml/XmlTree.java

1    package classUtils.pack.beans.xml; 
2     
3    import classUtils.pack.util.ListEnumeration; 
4    import org.xml.sax.Attributes; 
5    import org.xml.sax.SAXException; 
6    import org.xml.sax.helpers.DefaultHandler; 
7     
8    import javax.swing.ImageIcon; 
9    import javax.swing.JFrame; 
10   import javax.swing.JTree; 
11   import javax.swing.tree.DefaultTreeCellRenderer; 
12   import javax.swing.tree.DefaultTreeModel; 
13   import javax.swing.tree.TreeNode; 
14   import javax.swing.tree.TreePath; 
15   import javax.xml.parsers.ParserConfigurationException; 
16   import javax.xml.parsers.SAXParser; 
17   import javax.xml.parsers.SAXParserFactory; 
18   import java.io.ByteArrayInputStream; 
19   import java.io.ByteArrayOutputStream; 
20   import java.io.IOException; 
21   import java.io.InputStream; 
22   import java.util.ArrayList; 
23   import java.util.Enumeration; 
24   import java.util.List; 
25    
26   /** 
27    * <font color=red>NOT FUNCTIONAL YET</font>. A JavaBean to display and manage XML in a tree. 
28    *  
29    *  
30    * @author cris 
31    */ 
32   public class XmlTree extends JTree { 
33        
34       private static SAXParserFactory defaultSAXParserFactory; 
35       private TreeNode rootNode; 
36        
37    
38       /** 
39        * Constructor XmlTree. 
40        * @param xml 
41        */ 
42       public XmlTree(SAXParserFactory spf, String xml) throws SAXException, ParserConfigurationException, IOException { 
43           rootNode=new DocumentRootXmlTreeNode(); 
44           setModel(new DefaultTreeModel(rootNode)); 
45           SAXParser sp = spf.newSAXParser(); 
46           XmlTreeContentHandler ch = new XmlTreeContentHandler(this); 
47           sp.parse(new ByteArrayInputStream(xml.getBytes()), ch); 
48            
49           ((DefaultTreeCellRenderer)getCellRenderer()).setClosedIcon(new ElementXmlIcon()); 
50           ((DefaultTreeCellRenderer)getCellRenderer()).setOpenIcon(new ElementXmlIcon()); 
51           ((DefaultTreeCellRenderer)getCellRenderer()).setLeafIcon(new ElementXmlIcon()); 
52            
53       } 
54    
55        
56       public static void main(String[] args) throws Exception { 
57            
58           String xml =  
59               "<?xml version=\"1.0\"?>"+ 
60               "<sadun:test xmlns:sadun=\"http://www.sadun.org\">"+ 
61               " <sadun:internal-element>"+ 
62               "   TextNode"+ 
63               " </sadun:internal-element>"+ 
64               "</sadun:test>"; 
65            
66           JFrame frame = new JFrame(); 
67           SAXParserFactory spf = SAXParserFactory.newInstance(); 
68           spf.setValidating(false); 
69           XmlTree tree = new XmlTree(spf, xml); 
70           frame.getContentPane().add(tree); 
71           frame.pack(); 
72           frame.setVisible(true); 
73            
74            
75       } 
76        
77   } 
78    
79   abstract class BaseXmlTreeNode implements TreeNode { 
80        
81       private List children=new ArrayList(); 
82       private TreeNode parent; 
83        
84       protected BaseXmlTreeNode(TreeNode parent) { 
85           this.parent=parent; 
86       } 
87        
88       public void appendChild(BaseXmlTreeNode node) { 
89           insertChild(node, children.size()); 
90       } 
91        
92       public void insertChildOnTop(BaseXmlTreeNode node) { 
93           insertChild(node, 0); 
94       } 
95        
96       public void insertChild(TreeNode node, int index) { 
97           children.add(index, node); 
98       } 
99        
100      public void removeChild(int index) { 
101          children.remove(index); 
102      } 
103       
104      public void removeChild(TreeNode node) { 
105          int i; 
106          if ((i=getIndex(node))==-1) return; 
107          removeChild(i); 
108      } 
109       
110      /** 
111       * @see javax.swing.tree.TreeNode#children() 
112       */ 
113      public Enumeration children() { 
114          return new ListEnumeration(children); 
115      } 
116   
117      /** 
118       * @see javax.swing.tree.TreeNode#getChildAt(int) 
119       */ 
120      public TreeNode getChildAt(int index) { 
121          return (TreeNode)children.get(index); 
122      } 
123   
124      /** 
125       * @see javax.swing.tree.TreeNode#getChildCount() 
126       */ 
127      public int getChildCount() { 
128          return children.size(); 
129      } 
130   
131      /** 
132       * @see javax.swing.tree.TreeNode#getIndex(TreeNode) 
133       */ 
134      public int getIndex(TreeNode node) { 
135          return children.indexOf(node); 
136      } 
137   
138      /** 
139       * @see javax.swing.tree.TreeNode#getParent() 
140       */ 
141      public TreeNode getParent() { 
142          return parent; 
143      } 
144       
145      /** 
146       * Return the parent, as a BaseXmlTreeNode 
147       */ 
148      public BaseXmlTreeNode getXmlParent() { 
149          return (BaseXmlTreeNode)parent; 
150      } 
151       
152       
153   
154      /** 
155       * @see javax.swing.tree.TreeNode#isLeaf() 
156       */ 
157      public boolean isLeaf() { 
158          return children.size()==0; 
159      } 
160   
161      /** 
162       * @see javax.swing.tree.TreeNode#getAllowsChildren() 
163       */ 
164      public boolean getAllowsChildren() { 
165          return true; 
166      } 
167       
168      /** 
169       * Sets the parent. 
170       * @param parent The parent to set 
171       */ 
172      public void setParent(TreeNode parent) { 
173          if (parent==null) throw new RuntimeException("Cannot set parent node as null"); 
174          this.parent = parent; 
175      } 
176       
177      protected abstract String getLabel(); 
178       
179      public String toString() { return getLabel(); } 
180   
181  } 
182   
183  class DocumentRootXmlTreeNode extends BaseXmlTreeNode { 
184       
185      public DocumentRootXmlTreeNode() { 
186          super(null); 
187      } 
188       
189      protected String getLabel() { return "/";   } 
190       
191  } 
192   
193  abstract class BaseXmlTreeNodeWithNamespace extends BaseXmlTreeNode  { 
194       
195      private String nameSpaceURI; 
196       
197      protected BaseXmlTreeNodeWithNamespace(TreeNode parent, String nameSpaceURI) { 
198          super(parent); 
199          this.nameSpaceURI=nameSpaceURI; 
200      } 
201       
202      public boolean isPrefixed() { 
203          return nameSpaceURI!=null; 
204      } 
205   
206      /** 
207       * Returns the nameSpaceURI. 
208       * @return String 
209       */ 
210      public String getNameSpaceURI() { 
211          return nameSpaceURI; 
212      } 
213   
214      /** 
215       * Sets the nameSpaceURI. 
216       * @param nameSpaceURI The nameSpaceURI to set 
217       */ 
218      public void setNameSpaceURI(String nameSpaceURI) { 
219          this.nameSpaceURI = nameSpaceURI; 
220      } 
221       
222      protected String getNsPrefix() { 
223          if (isPrefixed()) return nameSpaceURI+":"; 
224          else return ""; 
225      } 
226       
227   
228  } 
229   
230  class ElementXmlTreeNode extends BaseXmlTreeNodeWithNamespace { 
231       
232      private String tag; 
233       
234      public ElementXmlTreeNode(BaseXmlTreeNode parent, String nameSpaceURI, String tag) { 
235          super(parent, nameSpaceURI); 
236          this.tag=tag; 
237      } 
238       
239      /** 
240       * Returns the tag. 
241       * @return String 
242       */ 
243      public String getTag() { 
244          return tag; 
245      } 
246   
247      /** 
248       * Sets the tag. 
249       * @param tag The tag to set 
250       */ 
251      public void setTag(String tag) { 
252          this.tag = tag; 
253      } 
254       
255      protected String getLabel() { return "<"+getNsPrefix()+tag+">"; } 
256   
257  } 
258   
259  class AttributeXmlTreeNode extends BaseXmlTreeNodeWithNamespace { 
260       
261      private String name; 
262      private String value; 
263       
264      public AttributeXmlTreeNode(BaseXmlTreeNode parent, String name, String value) { 
265          super(parent, null); 
266          this.name=name; 
267          this.value=value; 
268      } 
269       
270      /** 
271       * Returns the name. 
272       * @return String 
273       */ 
274      public String getName() { 
275          return name; 
276      } 
277   
278      /** 
279       * Returns the value. 
280       * @return String 
281       */ 
282      public String getValue() { 
283          return value; 
284      } 
285   
286      /** 
287       * Sets the name. 
288       * @param name The name to set 
289       */ 
290      public void setName(String name) { 
291          this.name = name; 
292      } 
293   
294      /** 
295       * Sets the value. 
296       * @param value The value to set 
297       */ 
298      public void setValue(String value) { 
299          this.value = value; 
300      } 
301       
302      protected String getLabel() { return "@"+name+"="+value; } 
303  } 
304   
305  class TextXmlTreeNode extends BaseXmlTreeNode  { 
306       
307      private String text; 
308       
309      public TextXmlTreeNode(BaseXmlTreeNode parent, String text) { 
310          super(parent); 
311          this.text=text; 
312      } 
313      /** 
314       * Returns the text. 
315       * @return String 
316       */ 
317      public String getText() { 
318          return text; 
319      } 
320   
321      /** 
322       * Sets the text. 
323       * @param text The text to set 
324       */ 
325      public void setText(String text) { 
326          this.text = text; 
327      } 
328       
329      protected String getLabel() { return "TEXT:"+text; } 
330  } 
331   
332  class XmlTreeContentHandler extends DefaultHandler { 
333       
334      private StringBuffer sb = new StringBuffer(); 
335      private JTree tree; 
336      private BaseXmlTreeNode currentNode; 
337      private TreePath currentPath; 
338   
339       
340      public XmlTreeContentHandler(JTree tree) { 
341          this.tree=tree; 
342          // Expect the root node to be DocumentRootXmlTreeNode 
343          if (! (tree.getModel()  instanceof DefaultTreeModel))  
344              throw new RuntimeException("The given JTree has not a DefaultTreeModel"); 
345          DefaultTreeModel model = (DefaultTreeModel)tree.getModel(); 
346          if (model.getRoot() == null) 
347              model.setRoot(new DocumentRootXmlTreeNode()); 
348          else  
349              if (!(model.getRoot() instanceof DocumentRootXmlTreeNode)) 
350                  throw new RuntimeException("The given JTree has not a DocumentRootXmlTreeNode object as a root node"); 
351          this.currentNode=(DocumentRootXmlTreeNode)model.getRoot(); 
352          this.currentPath=new TreePath(currentNode); 
353      } 
354       
355      /** 
356       * @see org.xml.sax.ContentHandler#characters(char[], int, int) 
357       */ 
358      public void characters(char[] chars, int start, int len) 
359          throws SAXException { 
360              for(int i=start;i<start+len;i++) { 
361                  sb.append(chars[i]); 
362              } 
363      } 
364   
365      /** 
366       * @see org.xml.sax.ContentHandler#endDocument() 
367       */ 
368      public void endDocument() throws SAXException { 
369          currentNode=null; 
370      } 
371   
372      /** 
373       * @see org.xml.sax.ContentHandler#endElement(String, String, String) 
374       */ 
375      public void endElement(String nameSpaceURI, String localName, String qName) 
376          throws SAXException { 
377              TextXmlTreeNode txtNode = new TextXmlTreeNode(currentNode, sb.toString()); 
378              currentNode.appendChild(txtNode); 
379              sb.delete(0, sb.length()); 
380              //System.out.println("Expanding "+currentPath.pathByAddingChild(txtNode)); 
381              //tree.expandPath(currentPath.pathByAddingChild(txtNode)); 
382              currentNode=currentNode.getXmlParent(); 
383              currentPath=currentPath.getParentPath(); 
384      } 
385   
386      /** 
387       * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int) 
388       */ 
389      public void ignorableWhitespace(char[] arg0, int arg1, int arg2) 
390          throws SAXException { 
391      } 
392   
393      /** 
394       * @see org.xml.sax.ContentHandler#processingInstruction(String, String) 
395       */ 
396      public void processingInstruction(String arg0, String arg1) 
397          throws SAXException { 
398      } 
399   
400      /** 
401       * @see org.xml.sax.ContentHandler#startDocument() 
402       */ 
403      public void startDocument() throws SAXException { 
404           
405      } 
406   
407      /** 
408       * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes) 
409       */ 
410      public void startElement( 
411          String nameSpaceURI, 
412          String localName, 
413          String qName, 
414          Attributes atts) 
415          throws SAXException { 
416               
417              String []tmp=split(qName); 
418              ElementXmlTreeNode elemNode = new ElementXmlTreeNode( 
419                  currentNode, 
420                  tmp[0], 
421                  tmp[1]); 
422              currentNode.appendChild(elemNode); 
423              currentPath=currentPath.pathByAddingChild(currentNode); 
424              tree.expandPath(currentPath); 
425              for(int i=0;i<atts.getLength();i++) { 
426                  tmp=split(atts.getQName(i)); 
427                   
428                  AttributeXmlTreeNode attrNode = new AttributeXmlTreeNode( 
429                      elemNode, 
430                      tmp[1], 
431                      atts.getValue(i) 
432                  ); 
433                  elemNode.appendChild(attrNode); 
434              } 
435          currentNode=elemNode; 
436      } 
437       
438      private String [] split(String qName) throws SAXException { 
439          int z; 
440          String ns=null, name; 
441          if ((z=qName.indexOf(":"))!=-1) { 
442              ns=qName.substring(0, z); 
443              if (qName.length()>=z) 
444                  name=qName.substring(z+1); 
445              else throw new SAXException("Name can't be empty"); 
446          } else name=qName; 
447          return new String[] { ns, name }; 
448      } 
449   
450      /** 
451       * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String) 
452       */ 
453      public void startPrefixMapping(String arg0, String arg1) 
454          throws SAXException { 
455      } 
456   
457  } 
458   
459  abstract class XmlTreeIcon extends ImageIcon { 
460      protected XmlTreeIcon(String imgName) throws IOException { 
461          super(getImageBytes(imgName)); 
462      } 
463       
464      private static byte [] getImageBytes(String imgName) throws IOException { 
465           
466          ByteArrayOutputStream os = new ByteArrayOutputStream(); 
467          InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(imgName); 
468          int c; 
469          while((c=is.read())!=-1)  
470              os.write(c); 
471          is.close(); 
472          os.close(); 
473          return os.toByteArray(); 
474      } 
475  } 
476   
477  class ElementXmlIcon extends XmlTreeIcon { 
478      public ElementXmlIcon() throws IOException { super("element.jpg"); } 
479  } 
480   
481  class AttributeXmlIcon extends XmlTreeIcon { 
482      public AttributeXmlIcon() throws IOException { super("attribute.gif"); } 
483  } 
484   
485  class TextXmlIcon extends XmlTreeIcon { 
486      public TextXmlIcon() throws IOException { super("text.gif"); } 
487  }