View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2005 Open World Ltd
4   //
5   // This file is part of MillScript.
6   //
7   // MillScript is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
20  ////////////////////////////////////////////////////////////////////////////////
21  package org.millscript.millscript.datatypes;
22  
23  import org.millscript.commons.util.IList;
24  import org.millscript.commons.util.MapIterator;
25  import org.millscript.commons.util.list.IArrayList;
26  import org.millscript.commons.xml.api.Attributes;
27  import org.millscript.commons.xml.api.Name;
28  import org.millscript.millscript.render.Renderable;
29  import org.millscript.millscript.render.Renderer;
30  
31  import java.io.IOException;
32  import java.io.Serializable;
33  
34  /**
35   * XmlElement is a lightweight objects that plays the role of an XML element. It
36   * is deliberately NOT compatible with the W3C DOM interface.  That interface
37   * includes "back-pointers" from children to their parents -- a terrible design
38   * error that is slowly but surely being recognized as such.
39   *
40   * @see <a href="http://www.millscript.org/reference/millscript/implementation/">Implementation notes</a>
41   */
42  public final class XmlElement extends AbstractListAware implements Fragment, Renderable, Serializable {
43  
44      /**
45       * This is the ID from the release 10.2.0 for future compatibility.
46       */
47      private static final long serialVersionUID = -7905050793300162929L;
48  
49      /**
50       * This elements name.
51       */
52      private Name name;
53  
54      /**
55       * This elements attributes.
56       */
57      private Attributes attributes;
58  
59      /**
60       * This elements children.
61       */
62      private Object[] children;
63  
64      /**
65       * Constructs a new XML element with the specified name, attributes and
66       * children.
67       *
68       * @param n the XML elements name
69       * @param a the XML elements attributes
70       * @param c the XML elements children
71       */
72      public XmlElement( final Name n, final Attributes a, final Object[] c ) {
73          this.name = n;
74          this.attributes = a;
75          this.children = c;
76      }
77  
78      /**
79       * @see org.millscript.millscript.datatypes.ListAware#asList()
80       */
81      public IList asList() {
82          return new IArrayList< Object >( this.children, true );
83      }
84  
85      /**
86       * @see org.millscript.millscript.datatypes.ListAware#asOriginal(org.millscript.commons.util.IList)
87       */
88      public Object asOriginal( final IList< ? > x ) {
89          return new XmlElement( name, attributes, x.toArray() );
90      }
91  
92      /**
93       * Returns the child at the specified position in this XML element.
94       *
95       * @param n the position of the required child
96       * @return  the child at the specified position
97       */
98      public Object get( final int n ) {
99          return children[ n ];
100     }
101 
102     /**
103      * Returns a map containing all the elements attribute names and values.
104      *
105      * @return  a Map with this elements attribute name-value pairs
106      */
107     public Attributes getAttributes() {
108         return this.attributes;
109     }
110 
111     /**
112      * Returns an array of all this elements children.
113      *
114      * @return  an array of this elements children
115      */
116     public Object[] getChildren() {
117         return children;
118     }
119 
120     /**
121      * Returns this elements Name.
122      *
123      * @return  this elements <code>Name</code>
124      */
125     public Name getName() {
126         return this.name;
127     }
128 
129     /**
130      * Outputs an indent for the specified level. e.g. prints a required number
131      * of spaces.
132      *
133      * @param level the level of indentation
134      */
135     static void indent( final int level ) {
136         for ( int i = 0; i < level; i++ ) {
137             System.out.print( "|   " );
138         }
139     }
140 
141     /**
142      * @see org.millscript.millscript.render.Renderable#render(Renderer)
143      */
144     public void render( final Renderer r ) throws IOException {
145         r.renderXMLElement( this );
146     }
147 
148     /**
149      * @see org.millscript.millscript.datatypes.ListAware#sameAs(java.lang.Object)
150      */
151     public boolean sameAs( final Object x ) {
152         return x instanceof XmlElement;
153     }
154 
155     /**
156      * Returns the number of children this XML element has.
157      *
158      * @return  an int holding the number of children
159      */
160     public int size() {
161         return children.length;
162     }
163 
164     /**
165      * Returns the name of the XML element.
166      *
167      * @return a String containing the XML element name
168      */
169     public String tagName() {
170         // TODO - we should probably return the full Name here
171         return name.getQName();
172     }
173 
174     /**
175      * Returns the name of this XML element as an Atom.
176      *
177      * @return  an Atom for this XML elements name
178      */
179     public Atom tagWord() {
180         // TODO - we should probably return the full Name here
181         return Atom.make( name.getQName() );
182     }
183 
184     /**
185      * @see java.lang.Object#toString()
186      */
187     @Override
188     public String toString() {
189         Object[] kids = this.children;
190         final int nkids = kids.length;
191 
192         final StringBuffer sofar = new StringBuffer( "<" );
193         sofar.append( this.name.getQName() );
194         final MapIterator< Name, String > it = this.attributes.iterator( true );
195         while ( it.hasNext() ) {
196             sofar.append( " " );
197             sofar.append( it.nextKey().getQName() );
198             if ( it.currentValue() != null ) {
199                 sofar.append( "=\"" );
200                 sofar.append( it.currentValue() );
201                 sofar.append( "\"" );
202             }
203         }
204 
205         if ( nkids == 0 ) {
206             sofar.append( "/>" );
207         } else {
208             sofar.append( ">" );
209             for ( int i = 0; i < nkids; i++ ) {
210                 if ( kids[ i ] != null ) {
211                     sofar.append( kids[ i ] );
212                 }
213             }
214             sofar.append( "</" );
215             sofar.append( this.name.getQName() );
216             sofar.append( ">" );
217         }
218         return sofar.toString();
219     }
220 
221 }