KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mq > xml > XElement


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.mq.xml;
23
24 import java.util.Enumeration JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 import org.xml.sax.Attributes JavaDoc;
29
30 /**
31  * XElement provides an interface to an XML element. An XElement represents an
32  * XML element which contains: <br>
33  *
34  * <ul>
35  * <li> Name (required)
36  * <li> Attributes (optional)
37  * <li> character data (optional)
38  * <li> other elements (optional)
39  * </ul>
40  * <p>
41  *
42  * It is important to understand the diffrence between an "field" XElement and
43  * a non "field" XElement. If an XElement does not contain any sub elements, it
44  * is considered a "field" XElement. The <code>getField(String)</code> and
45  * <code>getValue()</code> functions will throw an XElementException if they
46  * are used on non "attribute" objects. This give you a little bit type
47  * checking (You'll get an exception if you try to access the character data of
48  * an element that has sub elements). <p>
49  *
50  * If XElement is not an field, then it contains other XElements and optionaly
51  * some text. The text data can be accessed with the <code>getText()</code>
52  * method and the sub elements with the <code>iterator()</code> or with <code>
53  * getElementXXX()</code> fuctions. Since XML and thus XElements provide a tree
54  * type data structure, traversing the tree to access leaf data can be
55  * cumbersom if you have a 'deep' tree. For example, you may have to do: <code>
56  * element.getElement("tree").getElement("branch").getElement("leaf")</code>
57  * access a XElement 3 levels deep in the tree. To access deep elements easier,
58  * XElements lets you use 'reletive' names to access deep elements. Using
59  * reletive names, you could access the same element in previous example doing:
60  * <code>element.getElement("tree/branch/leaf")</code> When using relative
61  * names, keep in mind that "." will get the current XElement, and ".." will
62  * get parent XElement. Very similar to how URLs work.
63  *
64  * @author Hiram Chirino (Cojonudo14@hotmail.com)
65  * @created August 16, 2001
66  * @version $Revision: 55382 $
67  */

68 public class XElement {
69
70    private XElement parent = null;
71    private String JavaDoc name = null;
72    private Hashtable JavaDoc metadata = new Hashtable JavaDoc();
73    private Vector JavaDoc contents = new Vector JavaDoc();
74    private final static String JavaDoc nl = System.getProperty( "line.separator" );
75
76    /**
77     * Constructs an empty object.
78     *
79     * @param objectName the tag or element name that this object represents.
80     */

81    public XElement( String JavaDoc objectName ) {
82       if ( objectName == null ) {
83          throw new NullPointerException JavaDoc();
84       }
85       name = objectName;
86       contents.addElement( new StringBuffer JavaDoc() );
87    }
88
89    /**
90     * Constructs an XElement with it's parent and metatags set.
91     *
92     * @param objectName the tag or element name that this object represents.
93     * @param atts Description of Parameter
94     */

95    public XElement( String JavaDoc objectName, Attributes JavaDoc atts ) {
96       if ( objectName == null ) {
97          throw new NullPointerException JavaDoc();
98       }
99       if ( atts == null ) {
100          throw new NullPointerException JavaDoc();
101       }
102       name = objectName;
103       contents.addElement( new StringBuffer JavaDoc() );
104       for ( int i = 0; i < atts.getLength(); i++ ) {
105          metadata.put( atts.getQName( i ), atts.getValue( i ) );
106          //metadata.put( atts.getLocalName( i ), atts.getValue( i ) );
107
}
108    }
109
110    /**
111     * Sets/Adds a metatag value Only metatags whose value is not empty will
112     * display when the <code>toString()</code> methods is called.
113     *
114     * @param key the name of the metatag
115     * @param value the value to set the metatag to.
116     */

117    public void setAttribute( String JavaDoc key, String JavaDoc value ) {
118       metadata.put( key, value );
119    }
120
121    /**
122     * Sets the object name
123     *
124     * @param newName
125     */

126    public void setName( String JavaDoc newName ) {
127       name = newName;
128    }
129
130    /**
131     * Gets the character data that was within this object. This fuction can
132     * only be used on objects that are attributes.
133     *
134     * @param value The new Value value
135     * @returns the character data contained within this
136     * object.
137     * @throws XElementException if the object was not an attribute object
138     */

139    public void setValue( String JavaDoc value )
140       throws XElementException {
141       if ( !isField() ) {
142          throw new XElementException( "" + getName() + " is not an attribute object" );
143       }
144       contents.setElementAt( new StringBuffer JavaDoc( value ), 0 );
145    }
146
147
148    /**
149     * Sets/Adds a attribute
150     *
151     * @param key the name of the attribute element
152     * @param value the value to set the attribute to.
153     * @exception XElementException Description of Exception
154     */

155    public void setField( String JavaDoc key, String JavaDoc value )
156       throws XElementException {
157       getElement( key ).setValue( value );
158    }
159
160    /**
161     * Returns the value of a meta data value.
162     *
163     * @param key Description of Parameter
164     * @return The Attribute value
165     * @returns the value of the metadata item, or "" if the item has not
166     * been set.
167     */

168    public String JavaDoc getAttribute( String JavaDoc key ) {
169       String JavaDoc t = ( String JavaDoc )metadata.get( key );
170       if ( t == null ) {
171          return "";
172       }
173       return t;
174    }
175
176    /**
177     * Returns the element name (tag name) of this XElement
178     *
179     * @return The Name value
180     * @returns
181     */

182    public java.lang.String JavaDoc getName() {
183       return name;
184    }
185
186    /**
187     * Get the parent of this object, or the object the contains this one.
188     *
189     * @return The Parent value
190     * @returns null if this object is not contained by any other XElement.
191     */

192    public XElement getParent() {
193       return parent;
194    }
195
196    /**
197     * Gets the TRIMMED character data that was within this object. This differs
198     * from getValue() in that:
199     * <UL>
200     * <LI> this fuction will work on attribute and non attribute XElements
201     *
202     * <LI> it will trim both ends of the character data before returning it.
203     *
204     * </UL>
205     *
206     *
207     * @return The Text value
208     * @returns the character data contained within this object.
209     */

210    public String JavaDoc getText() {
211       return contents.elementAt( 0 ).toString().trim();
212    }
213
214    /**
215     * Gets the character data that was within this object. This fuction can
216     * only be used on objects that are attributes.
217     *
218     * @return The Value value
219     * @returns the character data contained within this
220     * object.
221     * @throws XElementException if the object was not an attribute object
222     */

223    public String JavaDoc getValue()
224       throws XElementException {
225       if ( !isField() ) {
226          throw new XElementException( "" + getName() + " is not an attribute object" );
227       }
228       return contents.elementAt( 0 ).toString();
229    }
230
231    /**
232     * Returns the first object contained in this object named relativeName.
233     *
234     * @param relativeName The name of the object to find
235     * @return The Element value
236     * @returns the XElement named relativeName
237     * @throws XElementException if the object could not be found.
238     */

239    public XElement getElement( String JavaDoc relativeName )
240       throws XElementException {
241       if ( relativeName == null ) {
242          throw new NullPointerException JavaDoc();
243       }
244
245       String JavaDoc names[] = {null, relativeName};
246
247       // Does the name have a "/" in it?
248
String JavaDoc split[] = splitFront( relativeName, "/" );
249       if ( split != null ) {
250
251          // was it an absolute name? (started with a '/')
252
if ( split[0].length() == 0 ) {
253             // we are the parent
254
if ( parent == null ) {
255                split[0] = null;
256             }
257             // Let my parent handle the request.
258
else {
259                return parent.getElement( relativeName );
260             }
261          }
262
263          // did we have a trailing / in the name?
264
if ( split[1].length() == 0 ) {
265             // For the case of "/",
266
if ( split[0].equals( null ) ) {
267                return this;
268             }
269
270             //otherwise it is an error
271
// to leave a trailing /, for example tree/leaf/
272
throw new XElementException( "Invalid name (trailing '/') : " + relativeName );
273          }
274
275          names = split;
276       }
277
278       if ( names[0] == null ) {
279          for ( int i = 1; i < contents.size(); i++ ) {
280             XElement o = ( XElement )contents.elementAt( i );
281             if ( names[1].equals( o.getName() ) ) {
282                return o;
283             }
284          }
285       } else {
286          if ( names[0].equals( "." ) ) {
287             return getElement( names[1] );
288          } else if ( names[0].equals( ".." ) ) {
289             if ( parent != null ) {
290                return parent.getElement( names[1] );
291             } else {
292                throw new XElementException( "Invalid name (" + getName() + " has no parent) : " + relativeName );
293             }
294          } else {
295             for ( int i = 1; i < contents.size(); i++ ) {
296                XElement o = ( XElement )contents.elementAt( i );
297                if ( names[0].equals( o.getName() ) ) {
298                   return o.getElement( names[1] );
299                }
300             }
301          }
302       }
303
304       throw new XElementException( "Invalid name (" + getName() + " does not contain the name) : " + relativeName );
305    }
306
307
308    /**
309     * Gets the value of a contained attribute object.
310     *
311     * @param objectName The name of the attribute object.
312     * @return The Field value
313     * @returns the value of the attribute object.
314     * @throws XElementException if the object does not exist or if its not an
315     * attribute object.
316     */

317    public String JavaDoc getField( String JavaDoc objectName )
318       throws XElementException {
319       return getElement( objectName ).getValue();
320    }
321
322    /**
323     * Returns true if the object is an attribute object. An object is an
324     * attribute object if it does not contain any other objects.
325     *
326     * @return The Field value
327     * @returns true if the object is an attribute object.
328     */

329    public boolean isField() {
330       return contents.size() == 1;
331    }
332
333    /**
334     * Returns all the contained objects with the specified name.
335     *
336     * @param relativeName The name of the objects
337     * @return The ElementsNamed value
338     * @returns whose name is relativeName;
339     */

340    public java.util.Enumeration JavaDoc getElementsNamed( String JavaDoc relativeName ) {
341
342       Vector JavaDoc t = new Vector JavaDoc();
343       addElementsToVector( t, relativeName );
344       return t.elements();
345    }
346
347    /**
348     * Adds and appends string data to the objects text.
349     *
350     * @param data Description of Parameter
351     */

352    public void add( String JavaDoc data ) {
353       ( ( StringBuffer JavaDoc )contents.elementAt( 0 ) ).append( data );
354    }
355
356    /**
357     * Serializes this object into a string.
358     *
359     * @return Description of the Returned Value
360     */

361    public String JavaDoc toString() {
362       return toString( 0, true );
363    }
364
365    /**
366     * Adds an XElement to the set of XElements that are contained by this
367     * object.
368     *
369     * @param subObject
370     */

371    public void addElement( XElement subObject ) {
372       contents.addElement( subObject );
373       subObject.parent = this;
374    }
375
376    /**
377     * Adds an XElement to the set of XElements that are contained by this
378     * object.
379     *
380     * @param key The feature to be added to the Field attribute
381     * @param value The feature to be added to the Field attribute
382     */

383    public void addField( String JavaDoc key, String JavaDoc value ) {
384       XElement subObject = new XElement( key );
385       subObject.add( value );
386       addElement( subObject );
387    }
388
389    /**
390     * Tests to see if this object contains the specified object.
391     *
392     * @param objectName The name of the object.
393     * @return Description of the Returned Value
394     * @returns true if the object exits.
395     */

396    public boolean containsElement( String JavaDoc objectName ) {
397       try {
398          getElement( objectName );
399          return true;
400       } catch ( XElementException e ) {
401          return false;
402       }
403    }
404
405    /**
406     * Tests to see if this object contains the specified attribute object.
407     *
408     * @param objectName The name of the attribute object.
409     * @return Description of the Returned Value
410     * @returns true if the attribute exits.
411     */

412    public boolean containsField( String JavaDoc objectName ) {
413       try {
414          XElement obj = getElement( objectName );
415          return obj.isField();
416       } catch ( XElementException e ) {
417          return false;
418       }
419    }
420
421    /**
422     * Serializes this object into a string.
423     *
424     * @param nestingLevel how many tabs to prepend to output
425     * @param indent Description of Parameter
426     * @return Description of the Returned Value
427     */

428    public String JavaDoc toString( int nestingLevel, boolean indent ) {
429       try {
430          StringBuffer JavaDoc indentation = new StringBuffer JavaDoc();
431          StringBuffer JavaDoc rc = new StringBuffer JavaDoc();
432          if ( indent ) {
433             for ( int i = 0; i < nestingLevel; i++ ) {
434                indentation.append( '\t' );
435             }
436          }
437          rc.append( indentation.toString() );
438          rc.append( "<" );
439          rc.append( getName() );
440          Enumeration JavaDoc enumeration = metadata.keys();
441          while ( enumeration.hasMoreElements() ) {
442             String JavaDoc key = ( String JavaDoc )enumeration.nextElement();
443             String JavaDoc value = ( String JavaDoc )metadata.get( key );
444             rc.append( ' ' );
445             rc.append( key );
446             rc.append( "=\"" );
447             rc.append( metaValueEncode( value ) );
448             rc.append( '"' );
449          }
450          if ( isField() ) {
451             if ( getValue().length() == 0 ) {
452                rc.append( "/>" );
453                rc.append( nl );
454             } else {
455                rc.append( '>' );
456                rc.append( valueEncode( getValue() ) );
457                rc.append( "</" );
458                rc.append( getName() );
459                rc.append( '>' );
460                rc.append( nl );
461             }
462          } else {
463             rc.append( '>' );
464             rc.append( nl );
465             String JavaDoc text = getText();
466             if ( text.length() > 0 ) {
467                rc.append( indentation.toString() + "\t" );
468                rc.append( getText() );
469                rc.append( nl );
470             }
471             for ( int i = 1; i < contents.size(); i++ ) {
472                Object JavaDoc o = contents.elementAt( i );
473                rc.append( ( ( XElement )o ).toString( nestingLevel + 1, indent ) );
474             }
475             rc.append( indentation.toString() );
476             rc.append( "</" );
477             rc.append( getName() );
478             rc.append( '>' );
479             rc.append( nl );
480          }
481          return rc.toString();
482       } catch ( XElementException e ) {
483          // This should not occur!
484
e.printStackTrace();
485          System.exit( 1 );
486          return "";
487       }
488    }
489
490    /**
491     * Serializes this object into a XML document String.
492     *
493     * @param indent Description of Parameter
494     * @return Description of the Returned Value
495     */

496    public String JavaDoc toXML( boolean indent ) {
497       return
498             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + nl +
499             toString( 0, indent );
500    }
501
502    /**
503     * Removes this XElement from the parent.
504     *
505     * @throws XElementException if the object did not have a parent
506     */

507    public void removeFromParent()
508       throws XElementException {
509       if ( parent == null ) {
510          throw new XElementException( "" + getName() + " does not have a parent" );
511       }
512
513       parent.contents.remove( this );
514       parent = null;
515    }
516
517    /**
518     * @return Description of the Returned Value
519     * @returns an Enumeration of all the XElement conatained within this
520     * object.
521     */

522    public Enumeration JavaDoc elements() {
523       return getElementsNamed( "*" );
524    }
525
526    /**
527     * adds all the contains elements to the vector that match the relative
528     * name.
529     *
530     * @param t The feature to be added to the ElementsToVector
531     * attribute
532     * @param relativeName The feature to be added to the ElementsToVector
533     * attribute
534     */

535    private void addElementsToVector( Vector JavaDoc t, String JavaDoc relativeName ) {
536
537       String JavaDoc names[] = {null, relativeName};
538
539       // Does the name have a "/" in it?
540
String JavaDoc split[] = splitFront( relativeName, "/" );
541       if ( split != null ) {
542
543          // was it an absolute name? (started with a '/')
544
if ( split[0].length() == 0 ) {
545             // we are the parent
546
if ( parent == null ) {
547                split[0] = null;
548             } else {
549                // Let my parent handle the request.
550
parent.addElementsToVector( t, relativeName );
551                return;
552             }
553          }
554
555          // did we have a trailing / in the name?
556
if ( split[1].length() == 0 ) {
557             return;
558          }
559          names = split;
560       }
561
562       if ( names[0] == null ) {
563          if ( names[1].equals( "*" ) ) {
564             for ( int i = 1; i < contents.size(); i++ ) {
565                t.addElement( contents.elementAt( i ) );
566             }
567          } else {
568             for ( int i = 1; i < contents.size(); i++ ) {
569                XElement o = ( XElement )contents.elementAt( i );
570                if ( names[1].equals( o.getName() ) ) {
571                   t.addElement( o );
572                }
573             }
574          }
575       } else {
576          if ( names[0].equals( "." ) ) {
577             addElementsToVector( t, names[1] );
578             return;
579          } else if ( names[0].equals( ".." ) ) {
580             if ( parent != null ) {
581                parent.addElementsToVector( t, names[1] );
582             }
583             return;
584          } else {
585             for ( int i = 1; i < contents.size(); i++ ) {
586                XElement o = ( XElement )contents.elementAt( i );
587                if ( names[0].equals( o.getName() ) ) {
588                   o.addElementsToVector( t, names[1] );
589                }
590             }
591          }
592       }
593    }
594
595    /**
596     * Constructs an empty object.
597     *
598     * @param is Description of Parameter
599     * @return Description of the Returned Value
600     * @exception XElementException Description of Exception
601     * @exception java.io.IOException Description of Exception
602     */

603    public static XElement createFrom( java.io.InputStream JavaDoc is )
604       throws XElementException, java.io.IOException JavaDoc {
605 class MyRecordConsumer implements XElementConsumer {
606
607          XElement root = null;
608
609          public void documentEndEvent() {
610          }
611
612          public void documentStartEvent() {
613          }
614
615          public void recordReadEvent( XElement o ) {
616             root = o;
617          }
618       }
619
620       MyRecordConsumer consumer = new MyRecordConsumer();
621       XElementProducer producer = new XElementProducer( consumer );
622
623       try {
624          producer.parse( is );
625          if ( consumer.root == null ) {
626             throw new XElementException( "No root element" );
627          }
628          return consumer.root;
629       } catch ( java.io.IOException JavaDoc e ) {
630          throw e;
631       } catch ( Exception JavaDoc e ) {
632          throw new XElementException( "Parse Error: " + e );
633       }
634    }
635
636    /**
637     * Constructs an empty object.
638     *
639     * @param url Description of Parameter
640     * @return Description of the Returned Value
641     * @exception XElementException Description of Exception
642     * @exception java.io.IOException Description of Exception
643     */

644    public static XElement createFrom( java.net.URL JavaDoc url )
645       throws XElementException, java.io.IOException JavaDoc {
646 class MyRecordConsumer implements XElementConsumer {
647
648          XElement root = null;
649
650          public void documentEndEvent() {
651          }
652
653          public void documentStartEvent() {
654          }
655
656          public void recordReadEvent( XElement o ) {
657             root = o;
658          }
659       }
660
661       MyRecordConsumer consumer = new MyRecordConsumer();
662       XElementProducer producer = new XElementProducer( consumer );
663
664       try {
665          producer.parse( url );
666          if ( consumer.root == null ) {
667             throw new XElementException( "No root element" );
668          }
669          return consumer.root;
670       } catch ( java.io.IOException JavaDoc e ) {
671          throw e;
672       } catch ( Exception JavaDoc e ) {
673          throw new XElementException( "Parse Error: " + e );
674       }
675    }
676
677
678    private static String JavaDoc findAndReplace( String JavaDoc value, String JavaDoc searchStr, String JavaDoc replaceStr ) {
679       StringBuffer JavaDoc buffer = new StringBuffer JavaDoc( value.length() );
680       while ( value.length() > 0 ) {
681          int pos = value.indexOf( searchStr );
682          if ( pos != -1 ) {
683             buffer.append( value.substring( 0, pos ) );
684             buffer.append( replaceStr );
685             if ( pos + searchStr.length() < value.length() ) {
686                value = value.substring( pos + searchStr.length() );
687             } else {
688                value = "";
689             }
690          } else {
691             buffer.append( value );
692             value = "";
693          }
694       }
695       return buffer.toString();
696    }
697
698    private static String JavaDoc metaValueEncode( String JavaDoc value ) {
699       value = findAndReplace( value, "&", "&amp;" );
700       value = findAndReplace( value, "\"", "&quot;" );
701       value = findAndReplace( value, "'", "&apos;" );
702       return utf8Encode( value );
703    }
704
705
706    private static String JavaDoc utf8Encode( String JavaDoc value ) {
707       try {
708          //char buff[] = new char[value.length()];
709
//value.getChars( 0, buff.length, buff, 0 );
710
//sun.io.CharToByteUTF8 conv = new sun.io.CharToByteUTF8();
711
//byte b[] = conv.convertAll( buff );
712
return new String JavaDoc( value.getBytes("UTF-8") );
713       } catch ( Exception JavaDoc e ) {
714          return null;
715       }
716    }
717
718    private static String JavaDoc valueEncode( String JavaDoc value ) {
719       value = findAndReplace( value, "&", "&amp;" );
720       value = findAndReplace( value, "<", "&lt;" );
721       value = findAndReplace( value, ">", "&gt;" );
722       return utf8Encode( value );
723    }
724
725
726    private static String JavaDoc[] splitFront( String JavaDoc string, String JavaDoc splitMarker ) {
727
728       if ( string == null || splitMarker == null ) {
729          throw new NullPointerException JavaDoc();
730       }
731
732       String JavaDoc front;
733       String JavaDoc back;
734
735       int pos = string.indexOf( splitMarker );
736       if ( pos == -1 ) {
737          return null;
738       }
739
740       int l = splitMarker.length();
741       front = string.substring( 0, pos );
742       if ( pos + l >= string.length() ) {
743          back = "";
744       } else {
745          back = string.substring( pos + l );
746       }
747
748       String JavaDoc rc[] = {front, back};
749       return rc;
750    }
751    
752    public String JavaDoc getOptionalField( String JavaDoc field) throws XElementException {
753       if ( !containsField(field) )
754          return null;
755       return getField(field);
756    }
757
758    public void setOptionalField( String JavaDoc field, String JavaDoc value) throws XElementException {
759       if ( value == null ) {
760          if( containsField(field) )
761               getElement(field).removeFromParent();
762          return;
763       }
764       if( containsField(field) )
765         setField(field, value);
766       else
767         addField(field, value);
768    }
769    
770 }
771
Popular Tags