Source Code Cross Referenced for XMLElement.java in  » Parser » NanoXML » nanoxml » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Parser » NanoXML » nanoxml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* XMLElement.java
0002:         *
0003:         * $Revision: 1.4 $
0004:         * $Date: 2002/03/24 10:27:59 $
0005:         * $Name: RELEASE_2_2_1 $
0006:         *
0007:         * This file is part of NanoXML 2 Lite.
0008:         * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
0009:         *
0010:         * This software is provided 'as-is', without any express or implied warranty.
0011:         * In no event will the authors be held liable for any damages arising from the
0012:         * use of this software.
0013:         *
0014:         * Permission is granted to anyone to use this software for any purpose,
0015:         * including commercial applications, and to alter it and redistribute it
0016:         * freely, subject to the following restrictions:
0017:         *
0018:         *  1. The origin of this software must not be misrepresented; you must not
0019:         *     claim that you wrote the original software. If you use this software in
0020:         *     a product, an acknowledgment in the product documentation would be
0021:         *     appreciated but is not required.
0022:         *
0023:         *  2. Altered source versions must be plainly marked as such, and must not be
0024:         *     misrepresented as being the original software.
0025:         *
0026:         *  3. This notice may not be removed or altered from any source distribution.
0027:         *****************************************************************************/
0028:
0029:        package nanoxml;
0030:
0031:        import java.io.ByteArrayOutputStream;
0032:        import java.io.CharArrayReader;
0033:        import java.io.IOException;
0034:        import java.io.OutputStreamWriter;
0035:        import java.io.Reader;
0036:        import java.io.StringReader;
0037:        import java.io.Writer;
0038:        import java.util.Enumeration;
0039:        import java.util.Hashtable;
0040:        import java.util.Vector;
0041:
0042:        /**
0043:         * XMLElement is a representation of an XML object. The object is able to parse
0044:         * XML code.
0045:         * <P><DL>
0046:         * <DT><B>Parsing XML Data</B></DT>
0047:         * <DD>
0048:         * You can parse XML data using the following code:
0049:         * <UL><CODE>
0050:         * XMLElement xml = new XMLElement();<BR>
0051:         * FileReader reader = new FileReader("filename.xml");<BR>
0052:         * xml.parseFromReader(reader);
0053:         * </CODE></UL></DD></DL>
0054:         * <DL><DT><B>Retrieving Attributes</B></DT>
0055:         * <DD>
0056:         * You can enumerate the attributes of an element using the method
0057:         * {@link #enumerateAttributeNames() enumerateAttributeNames}.
0058:         * The attribute values can be retrieved using the method
0059:         * {@link #getStringAttribute(java.lang.String) getStringAttribute}.
0060:         * The following example shows how to list the attributes of an element:
0061:         * <UL><CODE>
0062:         * XMLElement element = ...;<BR>
0063:         * Enumeration enum = element.getAttributeNames();<BR>
0064:         * while (enum.hasMoreElements()) {<BR>
0065:         * &nbsp;&nbsp;&nbsp;&nbsp;String key = (String) enum.nextElement();<BR>
0066:         * &nbsp;&nbsp;&nbsp;&nbsp;String value = element.getStringAttribute(key);<BR>
0067:         * &nbsp;&nbsp;&nbsp;&nbsp;System.out.println(key + " = " + value);<BR>
0068:         * }
0069:         * </CODE></UL></DD></DL>
0070:         * <DL><DT><B>Retrieving Child Elements</B></DT>
0071:         * <DD>
0072:         * You can enumerate the children of an element using
0073:         * {@link #enumerateChildren() enumerateChildren}.
0074:         * The number of child elements can be retrieved using
0075:         * {@link #countChildren() countChildren}.
0076:         * </DD></DL>
0077:         * <DL><DT><B>Elements Containing Character Data</B></DT>
0078:         * <DD>
0079:         * If an elements contains character data, like in the following example:
0080:         * <UL><CODE>
0081:         * &lt;title&gt;The Title&lt;/title&gt;
0082:         * </CODE></UL>
0083:         * you can retrieve that data using the method
0084:         * {@link #getContent() getContent}.
0085:         * </DD></DL>
0086:         * <DL><DT><B>Subclassing XMLElement</B></DT>
0087:         * <DD>
0088:         * When subclassing XMLElement, you need to override the method
0089:         * {@link #createAnotherElement() createAnotherElement}
0090:         * which has to return a new copy of the receiver.
0091:         * </DD></DL>
0092:         * <P>
0093:         *
0094:         * @see nanoxml.XMLParseException
0095:         *
0096:         * @author Marc De Scheemaecker
0097:         *         &lt;<A href="mailto:cyberelf@mac.com">cyberelf@mac.com</A>&gt;
0098:         * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
0099:         */
0100:        public class XMLElement {
0101:
0102:            /**
0103:             * Serialization serial version ID.
0104:             */
0105:            static final long serialVersionUID = 6685035139346394777L;
0106:
0107:            /**
0108:             * Major version of NanoXML. Classes with the same major and minor
0109:             * version are binary compatible. Classes with the same major version
0110:             * are source compatible. If the major version is different, you may
0111:             * need to modify the client source code.
0112:             *
0113:             * @see nanoxml.XMLElement#NANOXML_MINOR_VERSION
0114:             */
0115:            public static final int NANOXML_MAJOR_VERSION = 2;
0116:
0117:            /**
0118:             * Minor version of NanoXML. Classes with the same major and minor
0119:             * version are binary compatible. Classes with the same major version
0120:             * are source compatible. If the major version is different, you may
0121:             * need to modify the client source code.
0122:             *
0123:             * @see nanoxml.XMLElement#NANOXML_MAJOR_VERSION
0124:             */
0125:            public static final int NANOXML_MINOR_VERSION = 2;
0126:
0127:            /**
0128:             * The attributes given to the element.
0129:             *
0130:             * <dl><dt><b>Invariants:</b></dt><dd>
0131:             * <ul><li>The field can be empty.
0132:             *     <li>The field is never <code>null</code>.
0133:             *     <li>The keys and the values are strings.
0134:             * </ul></dd></dl>
0135:             */
0136:            private Hashtable attributes;
0137:
0138:            /**
0139:             * Child elements of the element.
0140:             *
0141:             * <dl><dt><b>Invariants:</b></dt><dd>
0142:             * <ul><li>The field can be empty.
0143:             *     <li>The field is never <code>null</code>.
0144:             *     <li>The elements are instances of <code>XMLElement</code>
0145:             *         or a subclass of <code>XMLElement</code>.
0146:             * </ul></dd></dl>
0147:             */
0148:            private Vector children;
0149:
0150:            /**
0151:             * The name of the element.
0152:             *
0153:             * <dl><dt><b>Invariants:</b></dt><dd>
0154:             * <ul><li>The field is <code>null</code> iff the element is not
0155:             *         initialized by either parse or setName.
0156:             *     <li>If the field is not <code>null</code>, it's not empty.
0157:             *     <li>If the field is not <code>null</code>, it contains a valid
0158:             *         XML identifier.
0159:             * </ul></dd></dl>
0160:             */
0161:            private String name;
0162:
0163:            /**
0164:             * The #PCDATA content of the object.
0165:             *
0166:             * <dl><dt><b>Invariants:</b></dt><dd>
0167:             * <ul><li>The field is <code>null</code> iff the element is not a
0168:             *         #PCDATA element.
0169:             *     <li>The field can be any string, including the empty string.
0170:             * </ul></dd></dl>
0171:             */
0172:            private String contents;
0173:
0174:            /**
0175:             * Conversion table for &amp;...; entities. The keys are the entity names
0176:             * without the &amp; and ; delimiters.
0177:             *
0178:             * <dl><dt><b>Invariants:</b></dt><dd>
0179:             * <ul><li>The field is never <code>null</code>.
0180:             *     <li>The field always contains the following associations:
0181:             *         "lt"&nbsp;=&gt;&nbsp;"&lt;", "gt"&nbsp;=&gt;&nbsp;"&gt;",
0182:             *         "quot"&nbsp;=&gt;&nbsp;"\"", "apos"&nbsp;=&gt;&nbsp;"'",
0183:             *         "amp"&nbsp;=&gt;&nbsp;"&amp;"
0184:             *     <li>The keys are strings
0185:             *     <li>The values are char arrays
0186:             * </ul></dd></dl>
0187:             */
0188:            private Hashtable entities;
0189:
0190:            /**
0191:             * The line number where the element starts.
0192:             *
0193:             * <dl><dt><b>Invariants:</b></dt><dd>
0194:             * <ul><li><code>lineNr &gt= 0</code>
0195:             * </ul></dd></dl>
0196:             */
0197:            private int lineNr;
0198:
0199:            /**
0200:             * <code>true</code> if the case of the element and attribute names
0201:             * are case insensitive.
0202:             */
0203:            private boolean ignoreCase;
0204:
0205:            /**
0206:             * <code>true</code> if the leading and trailing whitespace of #PCDATA
0207:             * sections have to be ignored.
0208:             */
0209:            private boolean ignoreWhitespace;
0210:
0211:            /**
0212:             * Character read too much.
0213:             * This character provides push-back functionality to the input reader
0214:             * without having to use a PushbackReader.
0215:             * If there is no such character, this field is '\0'.
0216:             */
0217:            private char charReadTooMuch;
0218:
0219:            /**
0220:             * The reader provided by the caller of the parse method.
0221:             *
0222:             * <dl><dt><b>Invariants:</b></dt><dd>
0223:             * <ul><li>The field is not <code>null</code> while the parse method
0224:             *         is running.
0225:             * </ul></dd></dl>
0226:             */
0227:            private Reader reader;
0228:
0229:            /**
0230:             * The current line number in the source content.
0231:             *
0232:             * <dl><dt><b>Invariants:</b></dt><dd>
0233:             * <ul><li>parserLineNr &gt; 0 while the parse method is running.
0234:             * </ul></dd></dl>
0235:             */
0236:            private int parserLineNr;
0237:
0238:            /**
0239:             * Creates and initializes a new XML element.
0240:             * Calling the construction is equivalent to:
0241:             * <ul><code>new XMLElement(new Hashtable(), false, true)
0242:             * </code></ul>
0243:             *
0244:             * <dl><dt><b>Postconditions:</b></dt><dd>
0245:             * <ul><li>countChildren() => 0
0246:             *     <li>enumerateChildren() => empty enumeration
0247:             *     <li>enumeratePropertyNames() => empty enumeration
0248:             *     <li>getChildren() => empty vector
0249:             *     <li>getContent() => ""
0250:             *     <li>getLineNr() => 0
0251:             *     <li>getName() => null
0252:             * </ul></dd></dl>
0253:             *
0254:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable)
0255:             *         XMLElement(Hashtable)
0256:             * @see nanoxml.XMLElement#XMLElement(boolean)
0257:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean)
0258:             *         XMLElement(Hashtable, boolean)
0259:             */
0260:            public XMLElement() {
0261:                this (new Hashtable(), false, true, true);
0262:            }
0263:
0264:            /**
0265:             * Creates and initializes a new XML element.
0266:             * Calling the construction is equivalent to:
0267:             * <ul><code>new XMLElement(entities, false, true)
0268:             * </code></ul>
0269:             *
0270:             * @param entities
0271:             *     The entity conversion table.
0272:             *
0273:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0274:             * <ul><li><code>entities != null</code>
0275:             * </ul></dd></dl>
0276:             *
0277:             * <dl><dt><b>Postconditions:</b></dt><dd>
0278:             * <ul><li>countChildren() => 0
0279:             *     <li>enumerateChildren() => empty enumeration
0280:             *     <li>enumeratePropertyNames() => empty enumeration
0281:             *     <li>getChildren() => empty vector
0282:             *     <li>getContent() => ""
0283:             *     <li>getLineNr() => 0
0284:             *     <li>getName() => null
0285:             * </ul></dd></dl><dl>
0286:             *
0287:             * @see nanoxml.XMLElement#XMLElement()
0288:             * @see nanoxml.XMLElement#XMLElement(boolean)
0289:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean)
0290:             *         XMLElement(Hashtable, boolean)
0291:             */
0292:            public XMLElement(Hashtable entities) {
0293:                this (entities, false, true, true);
0294:            }
0295:
0296:            /**
0297:             * Creates and initializes a new XML element.
0298:             * Calling the construction is equivalent to:
0299:             * <ul><code>new XMLElement(new Hashtable(), skipLeadingWhitespace, true)
0300:             * </code></ul>
0301:             *
0302:             * @param skipLeadingWhitespace
0303:             *     <code>true</code> if leading and trailing whitespace in PCDATA
0304:             *     content has to be removed.
0305:             *
0306:             * </dl><dl><dt><b>Postconditions:</b></dt><dd>
0307:             * <ul><li>countChildren() => 0
0308:             *     <li>enumerateChildren() => empty enumeration
0309:             *     <li>enumeratePropertyNames() => empty enumeration
0310:             *     <li>getChildren() => empty vector
0311:             *     <li>getContent() => ""
0312:             *     <li>getLineNr() => 0
0313:             *     <li>getName() => null
0314:             * </ul></dd></dl><dl>
0315:             *
0316:             * @see nanoxml.XMLElement#XMLElement()
0317:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable)
0318:             *         XMLElement(Hashtable)
0319:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean)
0320:             *         XMLElement(Hashtable, boolean)
0321:             */
0322:            public XMLElement(boolean skipLeadingWhitespace) {
0323:                this (new Hashtable(), skipLeadingWhitespace, true, true);
0324:            }
0325:
0326:            /**
0327:             * Creates and initializes a new XML element.
0328:             * Calling the construction is equivalent to:
0329:             * <ul><code>new XMLElement(entities, skipLeadingWhitespace, true)
0330:             * </code></ul>
0331:             *
0332:             * @param entities
0333:             *     The entity conversion table.
0334:             * @param skipLeadingWhitespace
0335:             *     <code>true</code> if leading and trailing whitespace in PCDATA
0336:             *     content has to be removed.
0337:             *
0338:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0339:             * <ul><li><code>entities != null</code>
0340:             * </ul></dd></dl>
0341:             *
0342:             * <dl><dt><b>Postconditions:</b></dt><dd>
0343:             * <ul><li>countChildren() => 0
0344:             *     <li>enumerateChildren() => empty enumeration
0345:             *     <li>enumeratePropertyNames() => empty enumeration
0346:             *     <li>getChildren() => empty vector
0347:             *     <li>getContent() => ""
0348:             *     <li>getLineNr() => 0
0349:             *     <li>getName() => null
0350:             * </ul></dd></dl><dl>
0351:             *
0352:             * @see nanoxml.XMLElement#XMLElement()
0353:             * @see nanoxml.XMLElement#XMLElement(boolean)
0354:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable)
0355:             *         XMLElement(Hashtable)
0356:             */
0357:            public XMLElement(Hashtable entities, boolean skipLeadingWhitespace) {
0358:                this (entities, skipLeadingWhitespace, true, true);
0359:            }
0360:
0361:            /**
0362:             * Creates and initializes a new XML element.
0363:             *
0364:             * @param entities
0365:             *     The entity conversion table.
0366:             * @param skipLeadingWhitespace
0367:             *     <code>true</code> if leading and trailing whitespace in PCDATA
0368:             *     content has to be removed.
0369:             * @param ignoreCase
0370:             *     <code>true</code> if the case of element and attribute names have
0371:             *     to be ignored.
0372:             *
0373:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0374:             * <ul><li><code>entities != null</code>
0375:             * </ul></dd></dl>
0376:             *
0377:             * <dl><dt><b>Postconditions:</b></dt><dd>
0378:             * <ul><li>countChildren() => 0
0379:             *     <li>enumerateChildren() => empty enumeration
0380:             *     <li>enumeratePropertyNames() => empty enumeration
0381:             *     <li>getChildren() => empty vector
0382:             *     <li>getContent() => ""
0383:             *     <li>getLineNr() => 0
0384:             *     <li>getName() => null
0385:             * </ul></dd></dl><dl>
0386:             *
0387:             * @see nanoxml.XMLElement#XMLElement()
0388:             * @see nanoxml.XMLElement#XMLElement(boolean)
0389:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable)
0390:             *         XMLElement(Hashtable)
0391:             * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean)
0392:             *         XMLElement(Hashtable, boolean)
0393:             */
0394:            public XMLElement(Hashtable entities,
0395:                    boolean skipLeadingWhitespace, boolean ignoreCase) {
0396:                this (entities, skipLeadingWhitespace, true, ignoreCase);
0397:            }
0398:
0399:            /**
0400:             * Creates and initializes a new XML element.
0401:             * <P>
0402:             * This constructor should <I>only</I> be called from
0403:             * {@link #createAnotherElement() createAnotherElement}
0404:             * to create child elements.
0405:             *
0406:             * @param entities
0407:             *     The entity conversion table.
0408:             * @param skipLeadingWhitespace
0409:             *     <code>true</code> if leading and trailing whitespace in PCDATA
0410:             *     content has to be removed.
0411:             * @param fillBasicConversionTable
0412:             *     <code>true</code> if the basic entities need to be added to
0413:             *     the entity list.
0414:             * @param ignoreCase
0415:             *     <code>true</code> if the case of element and attribute names have
0416:             *     to be ignored.
0417:             *
0418:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0419:             * <ul><li><code>entities != null</code>
0420:             *     <li>if <code>fillBasicConversionTable == false</code>
0421:             *         then <code>entities</code> contains at least the following
0422:             *         entries: <code>amp</code>, <code>lt</code>, <code>gt</code>,
0423:             *         <code>apos</code> and <code>quot</code>
0424:             * </ul></dd></dl>
0425:             *
0426:             * <dl><dt><b>Postconditions:</b></dt><dd>
0427:             * <ul><li>countChildren() => 0
0428:             *     <li>enumerateChildren() => empty enumeration
0429:             *     <li>enumeratePropertyNames() => empty enumeration
0430:             *     <li>getChildren() => empty vector
0431:             *     <li>getContent() => ""
0432:             *     <li>getLineNr() => 0
0433:             *     <li>getName() => null
0434:             * </ul></dd></dl><dl>
0435:             *
0436:             * @see nanoxml.XMLElement#createAnotherElement()
0437:             */
0438:            protected XMLElement(Hashtable entities,
0439:                         boolean   skipLeadingWhitespace,
0440:                         boolean   fillBasicConversionTable,
0441:                         boolean   ignoreCase)
0442:    {
0443:        this .ignoreWhitespace = skipLeadingWhitespace;
0444:        this .ignoreCase = ignoreCase;
0445:        this .name = null;
0446:        this .contents = "";
0447:        this .attributes = new Hashtable();
0448:        this .children = new Vector();
0449:        this .entities = entities;
0450:        this .lineNr = 0;
0451:        Enumeration enum = this .entities.keys();
0452:        while (enum.hasMoreElements()) {
0453:            Object key = enum.nextElement();
0454:            Object value = this .entities.get(key);
0455:            if (value instanceof  String) {
0456:                value = ((String) value).toCharArray();
0457:                this .entities.put(key, value);
0458:            }
0459:        }
0460:        if (fillBasicConversionTable) {
0461:            this .entities.put("amp", new char[] { '&' });
0462:            this .entities.put("quot", new char[] { '"' });
0463:            this .entities.put("apos", new char[] { '\'' });
0464:            this .entities.put("lt", new char[] { '<' });
0465:            this .entities.put("gt", new char[] { '>' });
0466:        }
0467:    }
0468:
0469:            /**
0470:             * Adds a child element.
0471:             *
0472:             * @param child
0473:             *     The child element to add.
0474:             *
0475:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0476:             * <ul><li><code>child != null</code>
0477:             *     <li><code>child.getName() != null</code>
0478:             *     <li><code>child</code> does not have a parent element
0479:             * </ul></dd></dl>
0480:             *
0481:             * <dl><dt><b>Postconditions:</b></dt><dd>
0482:             * <ul><li>countChildren() => old.countChildren() + 1
0483:             *     <li>enumerateChildren() => old.enumerateChildren() + child
0484:             *     <li>getChildren() => old.enumerateChildren() + child
0485:             * </ul></dd></dl><dl>
0486:             *
0487:             * @see nanoxml.XMLElement#countChildren()
0488:             * @see nanoxml.XMLElement#enumerateChildren()
0489:             * @see nanoxml.XMLElement#getChildren()
0490:             * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement)
0491:             *         removeChild(XMLElement)
0492:             */
0493:            public void addChild(XMLElement child) {
0494:                this .children.addElement(child);
0495:            }
0496:
0497:            /**
0498:             * Adds or modifies an attribute.
0499:             *
0500:             * @param name
0501:             *     The name of the attribute.
0502:             * @param value
0503:             *     The value of the attribute.
0504:             *
0505:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0506:             * <ul><li><code>name != null</code>
0507:             *     <li><code>name</code> is a valid XML identifier
0508:             *     <li><code>value != null</code>
0509:             * </ul></dd></dl>
0510:             *
0511:             * <dl><dt><b>Postconditions:</b></dt><dd>
0512:             * <ul><li>enumerateAttributeNames()
0513:             *         => old.enumerateAttributeNames() + name
0514:             *     <li>getAttribute(name) => value
0515:             * </ul></dd></dl><dl>
0516:             *
0517:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
0518:             *         setDoubleAttribute(String, double)
0519:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
0520:             *         setIntAttribute(String, int)
0521:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0522:             * @see nanoxml.XMLElement#getAttribute(java.lang.String)
0523:             *         getAttribute(String)
0524:             * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object)
0525:             *         getAttribute(String, Object)
0526:             * @see nanoxml.XMLElement#getAttribute(java.lang.String,
0527:             *                                      java.util.Hashtable,
0528:             *                                      java.lang.String, boolean)
0529:             *         getAttribute(String, Hashtable, String, boolean)
0530:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String)
0531:             *         getStringAttribute(String)
0532:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0533:             *                                            java.lang.String)
0534:             *         getStringAttribute(String, String)
0535:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0536:             *                                            java.util.Hashtable,
0537:             *                                            java.lang.String, boolean)
0538:             *         getStringAttribute(String, Hashtable, String, boolean)
0539:             */
0540:            public void setAttribute(String name, Object value) {
0541:                if (this .ignoreCase) {
0542:                    name = name.toUpperCase();
0543:                }
0544:                this .attributes.put(name, value.toString());
0545:            }
0546:
0547:            /**
0548:             * Adds or modifies an attribute.
0549:             *
0550:             * @param name
0551:             *     The name of the attribute.
0552:             * @param value
0553:             *     The value of the attribute.
0554:             *
0555:             * @deprecated Use {@link #setAttribute(java.lang.String, java.lang.Object)
0556:             *             setAttribute} instead.
0557:             */
0558:            public void addProperty(String name, Object value) {
0559:                this .setAttribute(name, value);
0560:            }
0561:
0562:            /**
0563:             * Adds or modifies an attribute.
0564:             *
0565:             * @param name
0566:             *     The name of the attribute.
0567:             * @param value
0568:             *     The value of the attribute.
0569:             *
0570:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0571:             * <ul><li><code>name != null</code>
0572:             *     <li><code>name</code> is a valid XML identifier
0573:             * </ul></dd></dl>
0574:             *
0575:             * <dl><dt><b>Postconditions:</b></dt><dd>
0576:             * <ul><li>enumerateAttributeNames()
0577:             *         => old.enumerateAttributeNames() + name
0578:             *     <li>getIntAttribute(name) => value
0579:             * </ul></dd></dl><dl>
0580:             *
0581:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
0582:             *         setDoubleAttribute(String, double)
0583:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0584:             *         setAttribute(String, Object)
0585:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0586:             *         removeAttribute(String)
0587:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0588:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String)
0589:             *         getIntAttribute(String)
0590:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int)
0591:             *         getIntAttribute(String, int)
0592:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String,
0593:             *                                         java.util.Hashtable,
0594:             *                                         java.lang.String, boolean)
0595:             *         getIntAttribute(String, Hashtable, String, boolean)
0596:             */
0597:            public void setIntAttribute(String name, int value) {
0598:                if (this .ignoreCase) {
0599:                    name = name.toUpperCase();
0600:                }
0601:                this .attributes.put(name, Integer.toString(value));
0602:            }
0603:
0604:            /**
0605:             * Adds or modifies an attribute.
0606:             *
0607:             * @param name
0608:             *     The name of the attribute.
0609:             * @param value
0610:             *     The value of the attribute.
0611:             *
0612:             * @deprecated Use {@link #setIntAttribute(java.lang.String, int)
0613:             *             setIntAttribute} instead.
0614:             */
0615:            public void addProperty(String key, int value) {
0616:                this .setIntAttribute(key, value);
0617:            }
0618:
0619:            /**
0620:             * Adds or modifies an attribute.
0621:             *
0622:             * @param name
0623:             *     The name of the attribute.
0624:             * @param value
0625:             *     The value of the attribute.
0626:             *
0627:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0628:             * <ul><li><code>name != null</code>
0629:             *     <li><code>name</code> is a valid XML identifier
0630:             * </ul></dd></dl>
0631:             *
0632:             * <dl><dt><b>Postconditions:</b></dt><dd>
0633:             * <ul><li>enumerateAttributeNames()
0634:             *         => old.enumerateAttributeNames() + name
0635:             *     <li>getDoubleAttribute(name) => value
0636:             * </ul></dd></dl><dl>
0637:             *
0638:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
0639:             *         setIntAttribute(String, int)
0640:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0641:             *         setAttribute(String, Object)
0642:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0643:             *         removeAttribute(String)
0644:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0645:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String)
0646:             *         getDoubleAttribute(String)
0647:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double)
0648:             *         getDoubleAttribute(String, double)
0649:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String,
0650:             *                                            java.util.Hashtable,
0651:             *                                            java.lang.String, boolean)
0652:             *         getDoubleAttribute(String, Hashtable, String, boolean)
0653:             */
0654:            public void setDoubleAttribute(String name, double value) {
0655:                if (this .ignoreCase) {
0656:                    name = name.toUpperCase();
0657:                }
0658:                this .attributes.put(name, Double.toString(value));
0659:            }
0660:
0661:            /**
0662:             * Adds or modifies an attribute.
0663:             *
0664:             * @param name
0665:             *     The name of the attribute.
0666:             * @param value
0667:             *     The value of the attribute.
0668:             *
0669:             * @deprecated Use {@link #setDoubleAttribute(java.lang.String, double)
0670:             *             setDoubleAttribute} instead.
0671:             */
0672:            public void addProperty(String name, double value) {
0673:                this .setDoubleAttribute(name, value);
0674:            }
0675:
0676:            /**
0677:             * Returns the number of child elements of the element.
0678:             *
0679:             * <dl><dt><b>Postconditions:</b></dt><dd>
0680:             * <ul><li><code>result >= 0</code>
0681:             * </ul></dd></dl>
0682:             *
0683:             * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement)
0684:             *         addChild(XMLElement)
0685:             * @see nanoxml.XMLElement#enumerateChildren()
0686:             * @see nanoxml.XMLElement#getChildren()
0687:             * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement)
0688:             *         removeChild(XMLElement)
0689:             */
0690:            public int countChildren() {
0691:                return this .children.size();
0692:            }
0693:
0694:            /**
0695:             * Enumerates the attribute names.
0696:             *
0697:             * <dl><dt><b>Postconditions:</b></dt><dd>
0698:             * <ul><li><code>result != null</code>
0699:             * </ul></dd></dl>
0700:             *
0701:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
0702:             *         setDoubleAttribute(String, double)
0703:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
0704:             *         setIntAttribute(String, int)
0705:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0706:             *         setAttribute(String, Object)
0707:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0708:             *         removeAttribute(String)
0709:             * @see nanoxml.XMLElement#getAttribute(java.lang.String)
0710:             *         getAttribute(String)
0711:             * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object)
0712:             *         getAttribute(String, String)
0713:             * @see nanoxml.XMLElement#getAttribute(java.lang.String,
0714:             *                                      java.util.Hashtable,
0715:             *                                      java.lang.String, boolean)
0716:             *         getAttribute(String, Hashtable, String, boolean)
0717:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String)
0718:             *         getStringAttribute(String)
0719:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0720:             *                                            java.lang.String)
0721:             *         getStringAttribute(String, String)
0722:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0723:             *                                            java.util.Hashtable,
0724:             *                                            java.lang.String, boolean)
0725:             *         getStringAttribute(String, Hashtable, String, boolean)
0726:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String)
0727:             *         getIntAttribute(String)
0728:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int)
0729:             *         getIntAttribute(String, int)
0730:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String,
0731:             *                                         java.util.Hashtable,
0732:             *                                         java.lang.String, boolean)
0733:             *         getIntAttribute(String, Hashtable, String, boolean)
0734:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String)
0735:             *         getDoubleAttribute(String)
0736:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double)
0737:             *         getDoubleAttribute(String, double)
0738:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String,
0739:             *                                            java.util.Hashtable,
0740:             *                                            java.lang.String, boolean)
0741:             *         getDoubleAttribute(String, Hashtable, String, boolean)
0742:             * @see nanoxml.XMLElement#getBooleanAttribute(java.lang.String,
0743:             *                                             java.lang.String,
0744:             *                                             java.lang.String, boolean)
0745:             *         getBooleanAttribute(String, String, String, boolean)
0746:             */
0747:            public Enumeration enumerateAttributeNames() {
0748:                return this .attributes.keys();
0749:            }
0750:
0751:            /**
0752:             * Enumerates the attribute names.
0753:             *
0754:             * @deprecated Use {@link #enumerateAttributeNames()
0755:             *             enumerateAttributeNames} instead.
0756:             */
0757:            public Enumeration enumeratePropertyNames() {
0758:                return this .enumerateAttributeNames();
0759:            }
0760:
0761:            /**
0762:             * Enumerates the child elements.
0763:             *
0764:             * <dl><dt><b>Postconditions:</b></dt><dd>
0765:             * <ul><li><code>result != null</code>
0766:             * </ul></dd></dl>
0767:             *
0768:             * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement)
0769:             *         addChild(XMLElement)
0770:             * @see nanoxml.XMLElement#countChildren()
0771:             * @see nanoxml.XMLElement#getChildren()
0772:             * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement)
0773:             *         removeChild(XMLElement)
0774:             */
0775:            public Enumeration enumerateChildren() {
0776:                return this .children.elements();
0777:            }
0778:
0779:            /**
0780:             * Returns the child elements as a Vector. It is safe to modify this
0781:             * Vector.
0782:             *
0783:             * <dl><dt><b>Postconditions:</b></dt><dd>
0784:             * <ul><li><code>result != null</code>
0785:             * </ul></dd></dl>
0786:             *
0787:             * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement)
0788:             *         addChild(XMLElement)
0789:             * @see nanoxml.XMLElement#countChildren()
0790:             * @see nanoxml.XMLElement#enumerateChildren()
0791:             * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement)
0792:             *         removeChild(XMLElement)
0793:             */
0794:            public Vector getChildren() {
0795:                try {
0796:                    return (Vector) this .children.clone();
0797:                } catch (Exception e) {
0798:                    // this never happens, however, some Java compilers are so
0799:                    // braindead that they require this exception clause
0800:                    return null;
0801:                }
0802:            }
0803:
0804:            /**
0805:             * Returns the PCDATA content of the object. If there is no such content,
0806:             * <CODE>null</CODE> is returned.
0807:             *
0808:             * @deprecated Use {@link #getContent() getContent} instead.
0809:             */
0810:            public String getContents() {
0811:                return this .getContent();
0812:            }
0813:
0814:            /**
0815:             * Returns the PCDATA content of the object. If there is no such content,
0816:             * <CODE>null</CODE> is returned.
0817:             *
0818:             * @see nanoxml.XMLElement#setContent(java.lang.String)
0819:             *         setContent(String)
0820:             */
0821:            public String getContent() {
0822:                return this .contents;
0823:            }
0824:
0825:            /**
0826:             * Returns the line nr in the source data on which the element is found.
0827:             * This method returns <code>0</code> there is no associated source data.
0828:             *
0829:             * <dl><dt><b>Postconditions:</b></dt><dd>
0830:             * <ul><li><code>result >= 0</code>
0831:             * </ul></dd></dl>
0832:             */
0833:            public int getLineNr() {
0834:                return this .lineNr;
0835:            }
0836:
0837:            /**
0838:             * Returns an attribute of the element.
0839:             * If the attribute doesn't exist, <code>null</code> is returned.
0840:             *
0841:             * @param name The name of the attribute.
0842:             *
0843:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0844:             * <ul><li><code>name != null</code>
0845:             *     <li><code>name</code> is a valid XML identifier
0846:             * </ul></dd></dl><dl>
0847:             *
0848:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0849:             *         setAttribute(String, Object)
0850:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0851:             *         removeAttribute(String)
0852:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0853:             * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object)
0854:             *         getAttribute(String, Object)
0855:             * @see nanoxml.XMLElement#getAttribute(java.lang.String,
0856:             *                                      java.util.Hashtable,
0857:             *                                      java.lang.String, boolean)
0858:             *         getAttribute(String, Hashtable, String, boolean)
0859:             */
0860:            public Object getAttribute(String name) {
0861:                return this .getAttribute(name, null);
0862:            }
0863:
0864:            /**
0865:             * Returns an attribute of the element.
0866:             * If the attribute doesn't exist, <code>defaultValue</code> is returned.
0867:             *
0868:             * @param name         The name of the attribute.
0869:             * @param defaultValue Key to use if the attribute is missing.
0870:             *
0871:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0872:             * <ul><li><code>name != null</code>
0873:             *     <li><code>name</code> is a valid XML identifier
0874:             * </ul></dd></dl><dl>
0875:             *
0876:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0877:             *         setAttribute(String, Object)
0878:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0879:             *         removeAttribute(String)
0880:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0881:             * @see nanoxml.XMLElement#getAttribute(java.lang.String)
0882:             *         getAttribute(String)
0883:             * @see nanoxml.XMLElement#getAttribute(java.lang.String,
0884:             *                                      java.util.Hashtable,
0885:             *                                      java.lang.String, boolean)
0886:             *         getAttribute(String, Hashtable, String, boolean)
0887:             */
0888:            public Object getAttribute(String name, Object defaultValue) {
0889:                if (this .ignoreCase) {
0890:                    name = name.toUpperCase();
0891:                }
0892:                Object value = this .attributes.get(name);
0893:                if (value == null) {
0894:                    value = defaultValue;
0895:                }
0896:                return value;
0897:            }
0898:
0899:            /**
0900:             * Returns an attribute by looking up a key in a hashtable.
0901:             * If the attribute doesn't exist, the value corresponding to defaultKey
0902:             * is returned.
0903:             * <P>
0904:             * As an example, if valueSet contains the mapping <code>"one" =>
0905:             * "1"</code>
0906:             * and the element contains the attribute <code>attr="one"</code>, then
0907:             * <code>getAttribute("attr", mapping, defaultKey, false)</code> returns
0908:             * <code>"1"</code>.
0909:             *
0910:             * @param name
0911:             *     The name of the attribute.
0912:             * @param valueSet
0913:             *     Hashtable mapping keys to values.
0914:             * @param defaultKey
0915:             *     Key to use if the attribute is missing.
0916:             * @param allowLiterals
0917:             *     <code>true</code> if literals are valid.
0918:             *
0919:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0920:             * <ul><li><code>name != null</code>
0921:             *     <li><code>name</code> is a valid XML identifier
0922:             *     <li><code>valueSet</code> != null
0923:             *     <li>the keys of <code>valueSet</code> are strings
0924:             * </ul></dd></dl><dl>
0925:             *
0926:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0927:             *         setAttribute(String, Object)
0928:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0929:             *         removeAttribute(String)
0930:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0931:             * @see nanoxml.XMLElement#getAttribute(java.lang.String)
0932:             *         getAttribute(String)
0933:             * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object)
0934:             *         getAttribute(String, Object)
0935:             */
0936:            public Object getAttribute(String name, Hashtable valueSet,
0937:                    String defaultKey, boolean allowLiterals) {
0938:                if (this .ignoreCase) {
0939:                    name = name.toUpperCase();
0940:                }
0941:                Object key = this .attributes.get(name);
0942:                Object result;
0943:                if (key == null) {
0944:                    key = defaultKey;
0945:                }
0946:                result = valueSet.get(key);
0947:                if (result == null) {
0948:                    if (allowLiterals) {
0949:                        result = key;
0950:                    } else {
0951:                        throw this .invalidValue(name, (String) key);
0952:                    }
0953:                }
0954:                return result;
0955:            }
0956:
0957:            /**
0958:             * Returns an attribute of the element.
0959:             * If the attribute doesn't exist, <code>null</code> is returned.
0960:             *
0961:             * @param name The name of the attribute.
0962:             *
0963:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0964:             * <ul><li><code>name != null</code>
0965:             *     <li><code>name</code> is a valid XML identifier
0966:             * </ul></dd></dl><dl>
0967:             *
0968:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0969:             *         setAttribute(String, Object)
0970:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
0971:             *         removeAttribute(String)
0972:             * @see nanoxml.XMLElement#enumerateAttributeNames()
0973:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0974:             *                                            java.lang.String)
0975:             *         getStringAttribute(String, String)
0976:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
0977:             *                                            java.util.Hashtable,
0978:             *                                            java.lang.String, boolean)
0979:             *         getStringAttribute(String, Hashtable, String, boolean)
0980:             */
0981:            public String getStringAttribute(String name) {
0982:                return this .getStringAttribute(name, null);
0983:            }
0984:
0985:            /**
0986:             * Returns an attribute of the element.
0987:             * If the attribute doesn't exist, <code>defaultValue</code> is returned.
0988:             *
0989:             * @param name         The name of the attribute.
0990:             * @param defaultValue Key to use if the attribute is missing.
0991:             *
0992:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
0993:             * <ul><li><code>name != null</code>
0994:             *     <li><code>name</code> is a valid XML identifier
0995:             * </ul></dd></dl><dl>
0996:             *
0997:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
0998:             *         setAttribute(String, Object)
0999:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
1000:             *         removeAttribute(String)
1001:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1002:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String)
1003:             *         getStringAttribute(String)
1004:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
1005:             *                                            java.util.Hashtable,
1006:             *                                            java.lang.String, boolean)
1007:             *         getStringAttribute(String, Hashtable, String, boolean)
1008:             */
1009:            public String getStringAttribute(String name, String defaultValue) {
1010:                return (String) this .getAttribute(name, defaultValue);
1011:            }
1012:
1013:            /**
1014:             * Returns an attribute by looking up a key in a hashtable.
1015:             * If the attribute doesn't exist, the value corresponding to defaultKey
1016:             * is returned.
1017:             * <P>
1018:             * As an example, if valueSet contains the mapping <code>"one" =>
1019:             * "1"</code>
1020:             * and the element contains the attribute <code>attr="one"</code>, then
1021:             * <code>getAttribute("attr", mapping, defaultKey, false)</code> returns
1022:             * <code>"1"</code>.
1023:             *
1024:             * @param name
1025:             *     The name of the attribute.
1026:             * @param valueSet
1027:             *     Hashtable mapping keys to values.
1028:             * @param defaultKey
1029:             *     Key to use if the attribute is missing.
1030:             * @param allowLiterals
1031:             *     <code>true</code> if literals are valid.
1032:             *
1033:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1034:             * <ul><li><code>name != null</code>
1035:             *     <li><code>name</code> is a valid XML identifier
1036:             *     <li><code>valueSet</code> != null
1037:             *     <li>the keys of <code>valueSet</code> are strings
1038:             *     <li>the values of <code>valueSet</code> are strings
1039:             * </ul></dd></dl><dl>
1040:             *
1041:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
1042:             *         setAttribute(String, Object)
1043:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
1044:             *         removeAttribute(String)
1045:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1046:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String)
1047:             *         getStringAttribute(String)
1048:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
1049:             *                                            java.lang.String)
1050:             *         getStringAttribute(String, String)
1051:             */
1052:            public String getStringAttribute(String name, Hashtable valueSet,
1053:                    String defaultKey, boolean allowLiterals) {
1054:                return (String) this .getAttribute(name, valueSet, defaultKey,
1055:                        allowLiterals);
1056:            }
1057:
1058:            /**
1059:             * Returns an attribute of the element.
1060:             * If the attribute doesn't exist, <code>0</code> is returned.
1061:             *
1062:             * @param name The name of the attribute.
1063:             *
1064:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1065:             * <ul><li><code>name != null</code>
1066:             *     <li><code>name</code> is a valid XML identifier
1067:             * </ul></dd></dl><dl>
1068:             *
1069:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
1070:             *         setIntAttribute(String, int)
1071:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1072:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int)
1073:             *         getIntAttribute(String, int)
1074:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String,
1075:             *                                         java.util.Hashtable,
1076:             *                                         java.lang.String, boolean)
1077:             *         getIntAttribute(String, Hashtable, String, boolean)
1078:             */
1079:            public int getIntAttribute(String name) {
1080:                return this .getIntAttribute(name, 0);
1081:            }
1082:
1083:            /**
1084:             * Returns an attribute of the element.
1085:             * If the attribute doesn't exist, <code>defaultValue</code> is returned.
1086:             *
1087:             * @param name         The name of the attribute.
1088:             * @param defaultValue Key to use if the attribute is missing.
1089:             *
1090:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1091:             * <ul><li><code>name != null</code>
1092:             *     <li><code>name</code> is a valid XML identifier
1093:             * </ul></dd></dl><dl>
1094:             *
1095:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
1096:             *         setIntAttribute(String, int)
1097:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1098:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String)
1099:             *         getIntAttribute(String)
1100:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String,
1101:             *                                         java.util.Hashtable,
1102:             *                                         java.lang.String, boolean)
1103:             *         getIntAttribute(String, Hashtable, String, boolean)
1104:             */
1105:            public int getIntAttribute(String name, int defaultValue) {
1106:                if (this .ignoreCase) {
1107:                    name = name.toUpperCase();
1108:                }
1109:                String value = (String) this .attributes.get(name);
1110:                if (value == null) {
1111:                    return defaultValue;
1112:                } else {
1113:                    try {
1114:                        return Integer.parseInt(value);
1115:                    } catch (NumberFormatException e) {
1116:                        throw this .invalidValue(name, value);
1117:                    }
1118:                }
1119:            }
1120:
1121:            /**
1122:             * Returns an attribute by looking up a key in a hashtable.
1123:             * If the attribute doesn't exist, the value corresponding to defaultKey
1124:             * is returned.
1125:             * <P>
1126:             * As an example, if valueSet contains the mapping <code>"one" => 1</code>
1127:             * and the element contains the attribute <code>attr="one"</code>, then
1128:             * <code>getIntAttribute("attr", mapping, defaultKey, false)</code> returns
1129:             * <code>1</code>.
1130:             *
1131:             * @param name
1132:             *     The name of the attribute.
1133:             * @param valueSet
1134:             *     Hashtable mapping keys to values.
1135:             * @param defaultKey
1136:             *     Key to use if the attribute is missing.
1137:             * @param allowLiteralNumbers
1138:             *     <code>true</code> if literal numbers are valid.
1139:             *
1140:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1141:             * <ul><li><code>name != null</code>
1142:             *     <li><code>name</code> is a valid XML identifier
1143:             *     <li><code>valueSet</code> != null
1144:             *     <li>the keys of <code>valueSet</code> are strings
1145:             *     <li>the values of <code>valueSet</code> are Integer objects
1146:             *     <li><code>defaultKey</code> is either <code>null</code>, a
1147:             *         key in <code>valueSet</code> or an integer.
1148:             * </ul></dd></dl><dl>
1149:             *
1150:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
1151:             *         setIntAttribute(String, int)
1152:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1153:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String)
1154:             *         getIntAttribute(String)
1155:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int)
1156:             *         getIntAttribute(String, int)
1157:             */
1158:            public int getIntAttribute(String name, Hashtable valueSet,
1159:                    String defaultKey, boolean allowLiteralNumbers) {
1160:                if (this .ignoreCase) {
1161:                    name = name.toUpperCase();
1162:                }
1163:                Object key = this .attributes.get(name);
1164:                Integer result;
1165:                if (key == null) {
1166:                    key = defaultKey;
1167:                }
1168:                try {
1169:                    result = (Integer) valueSet.get(key);
1170:                } catch (ClassCastException e) {
1171:                    throw this .invalidValueSet(name);
1172:                }
1173:                if (result == null) {
1174:                    if (!allowLiteralNumbers) {
1175:                        throw this .invalidValue(name, (String) key);
1176:                    }
1177:                    try {
1178:                        result = Integer.valueOf((String) key);
1179:                    } catch (NumberFormatException e) {
1180:                        throw this .invalidValue(name, (String) key);
1181:                    }
1182:                }
1183:                return result.intValue();
1184:            }
1185:
1186:            /**
1187:             * Returns an attribute of the element.
1188:             * If the attribute doesn't exist, <code>0.0</code> is returned.
1189:             *
1190:             * @param name The name of the attribute.
1191:             *
1192:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1193:             * <ul><li><code>name != null</code>
1194:             *     <li><code>name</code> is a valid XML identifier
1195:             * </ul></dd></dl><dl>
1196:             *
1197:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
1198:             *         setDoubleAttribute(String, double)
1199:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1200:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double)
1201:             *         getDoubleAttribute(String, double)
1202:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String,
1203:             *                                            java.util.Hashtable,
1204:             *                                            java.lang.String, boolean)
1205:             *         getDoubleAttribute(String, Hashtable, String, boolean)
1206:             */
1207:            public double getDoubleAttribute(String name) {
1208:                return this .getDoubleAttribute(name, 0.);
1209:            }
1210:
1211:            /**
1212:             * Returns an attribute of the element.
1213:             * If the attribute doesn't exist, <code>defaultValue</code> is returned.
1214:             *
1215:             * @param name         The name of the attribute.
1216:             * @param defaultValue Key to use if the attribute is missing.
1217:             *
1218:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1219:             * <ul><li><code>name != null</code>
1220:             *     <li><code>name</code> is a valid XML identifier
1221:             * </ul></dd></dl><dl>
1222:             *
1223:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
1224:             *         setDoubleAttribute(String, double)
1225:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1226:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String)
1227:             *         getDoubleAttribute(String)
1228:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String,
1229:             *                                            java.util.Hashtable,
1230:             *                                            java.lang.String, boolean)
1231:             *         getDoubleAttribute(String, Hashtable, String, boolean)
1232:             */
1233:            public double getDoubleAttribute(String name, double defaultValue) {
1234:                if (this .ignoreCase) {
1235:                    name = name.toUpperCase();
1236:                }
1237:                String value = (String) this .attributes.get(name);
1238:                if (value == null) {
1239:                    return defaultValue;
1240:                } else {
1241:                    try {
1242:                        return Double.valueOf(value).doubleValue();
1243:                    } catch (NumberFormatException e) {
1244:                        throw this .invalidValue(name, value);
1245:                    }
1246:                }
1247:            }
1248:
1249:            /**
1250:             * Returns an attribute by looking up a key in a hashtable.
1251:             * If the attribute doesn't exist, the value corresponding to defaultKey
1252:             * is returned.
1253:             * <P>
1254:             * As an example, if valueSet contains the mapping <code>"one" =&gt;
1255:             * 1.0</code>
1256:             * and the element contains the attribute <code>attr="one"</code>, then
1257:             * <code>getDoubleAttribute("attr", mapping, defaultKey, false)</code>
1258:             * returns <code>1.0</code>.
1259:             *
1260:             * @param name
1261:             *     The name of the attribute.
1262:             * @param valueSet
1263:             *     Hashtable mapping keys to values.
1264:             * @param defaultKey
1265:             *     Key to use if the attribute is missing.
1266:             * @param allowLiteralNumbers
1267:             *     <code>true</code> if literal numbers are valid.
1268:             *
1269:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1270:             * <ul><li><code>name != null</code>
1271:             *     <li><code>name</code> is a valid XML identifier
1272:             *     <li><code>valueSet != null</code>
1273:             *     <li>the keys of <code>valueSet</code> are strings
1274:             *     <li>the values of <code>valueSet</code> are Double objects
1275:             *     <li><code>defaultKey</code> is either <code>null</code>, a
1276:             *         key in <code>valueSet</code> or a double.
1277:             * </ul></dd></dl><dl>
1278:             *
1279:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
1280:             *         setDoubleAttribute(String, double)
1281:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1282:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String)
1283:             *         getDoubleAttribute(String)
1284:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double)
1285:             *         getDoubleAttribute(String, double)
1286:             */
1287:            public double getDoubleAttribute(String name, Hashtable valueSet,
1288:                    String defaultKey, boolean allowLiteralNumbers) {
1289:                if (this .ignoreCase) {
1290:                    name = name.toUpperCase();
1291:                }
1292:                Object key = this .attributes.get(name);
1293:                Double result;
1294:                if (key == null) {
1295:                    key = defaultKey;
1296:                }
1297:                try {
1298:                    result = (Double) valueSet.get(key);
1299:                } catch (ClassCastException e) {
1300:                    throw this .invalidValueSet(name);
1301:                }
1302:                if (result == null) {
1303:                    if (!allowLiteralNumbers) {
1304:                        throw this .invalidValue(name, (String) key);
1305:                    }
1306:                    try {
1307:                        result = Double.valueOf((String) key);
1308:                    } catch (NumberFormatException e) {
1309:                        throw this .invalidValue(name, (String) key);
1310:                    }
1311:                }
1312:                return result.doubleValue();
1313:            }
1314:
1315:            /**
1316:             * Returns an attribute of the element.
1317:             * If the attribute doesn't exist, <code>defaultValue</code> is returned.
1318:             * If the value of the attribute is equal to <code>trueValue</code>,
1319:             * <code>true</code> is returned.
1320:             * If the value of the attribute is equal to <code>falseValue</code>,
1321:             * <code>false</code> is returned.
1322:             * If the value doesn't match <code>trueValue</code> or
1323:             * <code>falseValue</code>, an exception is thrown.
1324:             *
1325:             * @param name         The name of the attribute.
1326:             * @param trueValue    The value associated with <code>true</code>.
1327:             * @param falseValue   The value associated with <code>true</code>.
1328:             * @param defaultValue Value to use if the attribute is missing.
1329:             *
1330:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1331:             * <ul><li><code>name != null</code>
1332:             *     <li><code>name</code> is a valid XML identifier
1333:             *     <li><code>trueValue</code> and <code>falseValue</code>
1334:             *         are different strings.
1335:             * </ul></dd></dl><dl>
1336:             *
1337:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
1338:             *         setAttribute(String, Object)
1339:             * @see nanoxml.XMLElement#removeAttribute(java.lang.String)
1340:             *         removeAttribute(String)
1341:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1342:             */
1343:            public boolean getBooleanAttribute(String name, String trueValue,
1344:                    String falseValue, boolean defaultValue) {
1345:                if (this .ignoreCase) {
1346:                    name = name.toUpperCase();
1347:                }
1348:                Object value = this .attributes.get(name);
1349:                if (value == null) {
1350:                    return defaultValue;
1351:                } else if (value.equals(trueValue)) {
1352:                    return true;
1353:                } else if (value.equals(falseValue)) {
1354:                    return false;
1355:                } else {
1356:                    throw this .invalidValue(name, (String) value);
1357:                }
1358:            }
1359:
1360:            /**
1361:             * Returns an attribute by looking up a key in a hashtable.
1362:             *
1363:             * @deprecated Use {@link #getIntAttribute(java.lang.String,
1364:             *             java.util.Hashtable, java.lang.String, boolean)
1365:             *             getIntAttribute} instead.
1366:             */
1367:            public int getIntProperty(String name, Hashtable valueSet,
1368:                    String defaultKey) {
1369:                return this .getIntAttribute(name, valueSet, defaultKey, false);
1370:            }
1371:
1372:            /**
1373:             * Returns an attribute.
1374:             *
1375:             * @deprecated Use {@link #getStringAttribute(java.lang.String)
1376:             *             getStringAttribute} instead.
1377:             */
1378:            public String getProperty(String name) {
1379:                return this .getStringAttribute(name);
1380:            }
1381:
1382:            /**
1383:             * Returns an attribute.
1384:             *
1385:             * @deprecated Use {@link #getStringAttribute(java.lang.String,
1386:             *             java.lang.String) getStringAttribute} instead.
1387:             */
1388:            public String getProperty(String name, String defaultValue) {
1389:                return this .getStringAttribute(name, defaultValue);
1390:            }
1391:
1392:            /**
1393:             * Returns an attribute.
1394:             *
1395:             * @deprecated Use {@link #getIntAttribute(java.lang.String, int)
1396:             *             getIntAttribute} instead.
1397:             */
1398:            public int getProperty(String name, int defaultValue) {
1399:                return this .getIntAttribute(name, defaultValue);
1400:            }
1401:
1402:            /**
1403:             * Returns an attribute.
1404:             *
1405:             * @deprecated Use {@link #getDoubleAttribute(java.lang.String, double)
1406:             *             getDoubleAttribute} instead.
1407:             */
1408:            public double getProperty(String name, double defaultValue) {
1409:                return this .getDoubleAttribute(name, defaultValue);
1410:            }
1411:
1412:            /**
1413:             * Returns an attribute.
1414:             *
1415:             * @deprecated Use {@link #getBooleanAttribute(java.lang.String,
1416:             *             java.lang.String, java.lang.String, boolean)
1417:             *             getBooleanAttribute} instead.
1418:             */
1419:            public boolean getProperty(String key, String trueValue,
1420:                    String falseValue, boolean defaultValue) {
1421:                return this .getBooleanAttribute(key, trueValue, falseValue,
1422:                        defaultValue);
1423:            }
1424:
1425:            /**
1426:             * Returns an attribute by looking up a key in a hashtable.
1427:             *
1428:             * @deprecated Use {@link #getAttribute(java.lang.String,
1429:             *             java.util.Hashtable, java.lang.String, boolean)
1430:             *             getAttribute} instead.
1431:             */
1432:            public Object getProperty(String name, Hashtable valueSet,
1433:                    String defaultKey) {
1434:                return this .getAttribute(name, valueSet, defaultKey, false);
1435:            }
1436:
1437:            /**
1438:             * Returns an attribute by looking up a key in a hashtable.
1439:             *
1440:             * @deprecated Use {@link #getStringAttribute(java.lang.String,
1441:             *             java.util.Hashtable, java.lang.String, boolean)
1442:             *             getStringAttribute} instead.
1443:             */
1444:            public String getStringProperty(String name, Hashtable valueSet,
1445:                    String defaultKey) {
1446:                return this .getStringAttribute(name, valueSet, defaultKey,
1447:                        false);
1448:            }
1449:
1450:            /**
1451:             * Returns an attribute by looking up a key in a hashtable.
1452:             *
1453:             * @deprecated Use {@link #getIntAttribute(java.lang.String,
1454:             *             java.util.Hashtable, java.lang.String, boolean)
1455:             *             getIntAttribute} instead.
1456:             */
1457:            public int getSpecialIntProperty(String name, Hashtable valueSet,
1458:                    String defaultKey) {
1459:                return this .getIntAttribute(name, valueSet, defaultKey, true);
1460:            }
1461:
1462:            /**
1463:             * Returns an attribute by looking up a key in a hashtable.
1464:             *
1465:             * @deprecated Use {@link #getDoubleAttribute(java.lang.String,
1466:             *             java.util.Hashtable, java.lang.String, boolean)
1467:             *             getDoubleAttribute} instead.
1468:             */
1469:            public double getSpecialDoubleProperty(String name,
1470:                    Hashtable valueSet, String defaultKey) {
1471:                return this 
1472:                        .getDoubleAttribute(name, valueSet, defaultKey, true);
1473:            }
1474:
1475:            /**
1476:             * Returns the name of the element.
1477:             *
1478:             * @see nanoxml.XMLElement#setName(java.lang.String) setName(String)
1479:             */
1480:            public String getName() {
1481:                return this .name;
1482:            }
1483:
1484:            /**
1485:             * Returns the name of the element.
1486:             *
1487:             * @deprecated Use {@link #getName() getName} instead.
1488:             */
1489:            public String getTagName() {
1490:                return this .getName();
1491:            }
1492:
1493:            /**
1494:             * Reads one XML element from a java.io.Reader and parses it.
1495:             *
1496:             * @param reader
1497:             *     The reader from which to retrieve the XML data.
1498:             *
1499:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1500:             * <ul><li><code>reader != null</code>
1501:             *     <li><code>reader</code> is not closed
1502:             * </ul></dd></dl>
1503:             *
1504:             * <dl><dt><b>Postconditions:</b></dt><dd>
1505:             * <ul><li>the state of the receiver is updated to reflect the XML element
1506:             *         parsed from the reader
1507:             *     <li>the reader points to the first character following the last
1508:             *         '&gt;' character of the XML element
1509:             * </ul></dd></dl><dl>
1510:             *
1511:             * @throws java.io.IOException
1512:             *     If an error occured while reading the input.
1513:             * @throws nanoxml.XMLParseException
1514:             *     If an error occured while parsing the read data.
1515:             */
1516:            public void parseFromReader(Reader reader) throws IOException,
1517:                    XMLParseException {
1518:                this .parseFromReader(reader, /*startingLineNr*/1);
1519:            }
1520:
1521:            /**
1522:             * Reads one XML element from a java.io.Reader and parses it.
1523:             *
1524:             * @param reader
1525:             *     The reader from which to retrieve the XML data.
1526:             * @param startingLineNr
1527:             *     The line number of the first line in the data.
1528:             *
1529:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1530:             * <ul><li><code>reader != null</code>
1531:             *     <li><code>reader</code> is not closed
1532:             * </ul></dd></dl>
1533:             *
1534:             * <dl><dt><b>Postconditions:</b></dt><dd>
1535:             * <ul><li>the state of the receiver is updated to reflect the XML element
1536:             *         parsed from the reader
1537:             *     <li>the reader points to the first character following the last
1538:             *         '&gt;' character of the XML element
1539:             * </ul></dd></dl><dl>
1540:             *
1541:             * @throws java.io.IOException
1542:             *     If an error occured while reading the input.
1543:             * @throws nanoxml.XMLParseException
1544:             *     If an error occured while parsing the read data.
1545:             */
1546:            public void parseFromReader(Reader reader, int startingLineNr)
1547:                    throws IOException, XMLParseException {
1548:                this .name = null;
1549:                this .contents = "";
1550:                this .attributes = new Hashtable();
1551:                this .children = new Vector();
1552:                this .charReadTooMuch = '\0';
1553:                this .reader = reader;
1554:                this .parserLineNr = startingLineNr;
1555:
1556:                for (;;) {
1557:                    char ch = this .scanWhitespace();
1558:
1559:                    if (ch != '<') {
1560:                        throw this .expectedInput("<");
1561:                    }
1562:
1563:                    ch = this .readChar();
1564:
1565:                    if ((ch == '!') || (ch == '?')) {
1566:                        this .skipSpecialTag(0);
1567:                    } else {
1568:                        this .unreadChar(ch);
1569:                        this .scanElement(this );
1570:                        return;
1571:                    }
1572:                }
1573:            }
1574:
1575:            /**
1576:             * Reads one XML element from a String and parses it.
1577:             *
1578:             * @param reader
1579:             *     The reader from which to retrieve the XML data.
1580:             *
1581:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1582:             * <ul><li><code>string != null</code>
1583:             *     <li><code>string.length() &gt; 0</code>
1584:             * </ul></dd></dl>
1585:             *
1586:             * <dl><dt><b>Postconditions:</b></dt><dd>
1587:             * <ul><li>the state of the receiver is updated to reflect the XML element
1588:             *         parsed from the reader
1589:             * </ul></dd></dl><dl>
1590:             *
1591:             * @throws nanoxml.XMLParseException
1592:             *     If an error occured while parsing the string.
1593:             */
1594:            public void parseString(String string) throws XMLParseException {
1595:                try {
1596:                    this .parseFromReader(new StringReader(string),
1597:                    /*startingLineNr*/1);
1598:                } catch (IOException e) {
1599:                    // Java exception handling suxx
1600:                }
1601:            }
1602:
1603:            /**
1604:             * Reads one XML element from a String and parses it.
1605:             *
1606:             * @param reader
1607:             *     The reader from which to retrieve the XML data.
1608:             * @param offset
1609:             *     The first character in <code>string</code> to scan.
1610:             *
1611:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1612:             * <ul><li><code>string != null</code>
1613:             *     <li><code>offset &lt; string.length()</code>
1614:             *     <li><code>offset &gt;= 0</code>
1615:             * </ul></dd></dl>
1616:             *
1617:             * <dl><dt><b>Postconditions:</b></dt><dd>
1618:             * <ul><li>the state of the receiver is updated to reflect the XML element
1619:             *         parsed from the reader
1620:             * </ul></dd></dl><dl>
1621:             *
1622:             * @throws nanoxml.XMLParseException
1623:             *     If an error occured while parsing the string.
1624:             */
1625:            public void parseString(String string, int offset)
1626:                    throws XMLParseException {
1627:                this .parseString(string.substring(offset));
1628:            }
1629:
1630:            /**
1631:             * Reads one XML element from a String and parses it.
1632:             *
1633:             * @param reader
1634:             *     The reader from which to retrieve the XML data.
1635:             * @param offset
1636:             *     The first character in <code>string</code> to scan.
1637:             * @param end
1638:             *     The character where to stop scanning.
1639:             *     This character is not scanned.
1640:             *
1641:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1642:             * <ul><li><code>string != null</code>
1643:             *     <li><code>end &lt;= string.length()</code>
1644:             *     <li><code>offset &lt; end</code>
1645:             *     <li><code>offset &gt;= 0</code>
1646:             * </ul></dd></dl>
1647:             *
1648:             * <dl><dt><b>Postconditions:</b></dt><dd>
1649:             * <ul><li>the state of the receiver is updated to reflect the XML element
1650:             *         parsed from the reader
1651:             * </ul></dd></dl><dl>
1652:             *
1653:             * @throws nanoxml.XMLParseException
1654:             *     If an error occured while parsing the string.
1655:             */
1656:            public void parseString(String string, int offset, int end)
1657:                    throws XMLParseException {
1658:                this .parseString(string.substring(offset, end));
1659:            }
1660:
1661:            /**
1662:             * Reads one XML element from a String and parses it.
1663:             *
1664:             * @param reader
1665:             *     The reader from which to retrieve the XML data.
1666:             * @param offset
1667:             *     The first character in <code>string</code> to scan.
1668:             * @param end
1669:             *     The character where to stop scanning.
1670:             *     This character is not scanned.
1671:             * @param startingLineNr
1672:             *     The line number of the first line in the data.
1673:             *
1674:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1675:             * <ul><li><code>string != null</code>
1676:             *     <li><code>end &lt;= string.length()</code>
1677:             *     <li><code>offset &lt; end</code>
1678:             *     <li><code>offset &gt;= 0</code>
1679:             * </ul></dd></dl>
1680:             *
1681:             * <dl><dt><b>Postconditions:</b></dt><dd>
1682:             * <ul><li>the state of the receiver is updated to reflect the XML element
1683:             *         parsed from the reader
1684:             * </ul></dd></dl><dl>
1685:             *
1686:             * @throws nanoxml.XMLParseException
1687:             *     If an error occured while parsing the string.
1688:             */
1689:            public void parseString(String string, int offset, int end,
1690:                    int startingLineNr) throws XMLParseException {
1691:                string = string.substring(offset, end);
1692:                try {
1693:                    this .parseFromReader(new StringReader(string),
1694:                            startingLineNr);
1695:                } catch (IOException e) {
1696:                    // Java exception handling suxx
1697:                }
1698:            }
1699:
1700:            /**
1701:             * Reads one XML element from a char array and parses it.
1702:             *
1703:             * @param reader
1704:             *     The reader from which to retrieve the XML data.
1705:             * @param offset
1706:             *     The first character in <code>string</code> to scan.
1707:             * @param end
1708:             *     The character where to stop scanning.
1709:             *     This character is not scanned.
1710:             *
1711:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1712:             * <ul><li><code>input != null</code>
1713:             *     <li><code>end &lt;= input.length</code>
1714:             *     <li><code>offset &lt; end</code>
1715:             *     <li><code>offset &gt;= 0</code>
1716:             * </ul></dd></dl>
1717:             *
1718:             * <dl><dt><b>Postconditions:</b></dt><dd>
1719:             * <ul><li>the state of the receiver is updated to reflect the XML element
1720:             *         parsed from the reader
1721:             * </ul></dd></dl><dl>
1722:             *
1723:             * @throws nanoxml.XMLParseException
1724:             *     If an error occured while parsing the string.
1725:             */
1726:            public void parseCharArray(char[] input, int offset, int end)
1727:                    throws XMLParseException {
1728:                this .parseCharArray(input, offset, end, /*startingLineNr*/1);
1729:            }
1730:
1731:            /**
1732:             * Reads one XML element from a char array and parses it.
1733:             *
1734:             * @param reader
1735:             *     The reader from which to retrieve the XML data.
1736:             * @param offset
1737:             *     The first character in <code>string</code> to scan.
1738:             * @param end
1739:             *     The character where to stop scanning.
1740:             *     This character is not scanned.
1741:             * @param startingLineNr
1742:             *     The line number of the first line in the data.
1743:             *
1744:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1745:             * <ul><li><code>input != null</code>
1746:             *     <li><code>end &lt;= input.length</code>
1747:             *     <li><code>offset &lt; end</code>
1748:             *     <li><code>offset &gt;= 0</code>
1749:             * </ul></dd></dl>
1750:             *
1751:             * <dl><dt><b>Postconditions:</b></dt><dd>
1752:             * <ul><li>the state of the receiver is updated to reflect the XML element
1753:             *         parsed from the reader
1754:             * </ul></dd></dl><dl>
1755:             *
1756:             * @throws nanoxml.XMLParseException
1757:             *     If an error occured while parsing the string.
1758:             */
1759:            public void parseCharArray(char[] input, int offset, int end,
1760:                    int startingLineNr) throws XMLParseException {
1761:                try {
1762:                    Reader reader = new CharArrayReader(input, offset, end);
1763:                    this .parseFromReader(reader, startingLineNr);
1764:                } catch (IOException e) {
1765:                    // This exception will never happen.
1766:                }
1767:            }
1768:
1769:            /**
1770:             * Removes a child element.
1771:             *
1772:             * @param child
1773:             *     The child element to remove.
1774:             *
1775:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1776:             * <ul><li><code>child != null</code>
1777:             *     <li><code>child</code> is a child element of the receiver
1778:             * </ul></dd></dl>
1779:             *
1780:             * <dl><dt><b>Postconditions:</b></dt><dd>
1781:             * <ul><li>countChildren() => old.countChildren() - 1
1782:             *     <li>enumerateChildren() => old.enumerateChildren() - child
1783:             *     <li>getChildren() => old.enumerateChildren() - child
1784:             * </ul></dd></dl><dl>
1785:             *
1786:             * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement)
1787:             *         addChild(XMLElement)
1788:             * @see nanoxml.XMLElement#countChildren()
1789:             * @see nanoxml.XMLElement#enumerateChildren()
1790:             * @see nanoxml.XMLElement#getChildren()
1791:             */
1792:            public void removeChild(XMLElement child) {
1793:                this .children.removeElement(child);
1794:            }
1795:
1796:            /**
1797:             * Removes an attribute.
1798:             *
1799:             * @param name
1800:             *     The name of the attribute.
1801:             *
1802:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1803:             * <ul><li><code>name != null</code>
1804:             *     <li><code>name</code> is a valid XML identifier
1805:             * </ul></dd></dl>
1806:             *
1807:             * <dl><dt><b>Postconditions:</b></dt><dd>
1808:             * <ul><li>enumerateAttributeNames()
1809:             *         => old.enumerateAttributeNames() - name
1810:             *     <li>getAttribute(name) => <code>null</code>
1811:             * </ul></dd></dl><dl>
1812:             *
1813:             * @see nanoxml.XMLElement#enumerateAttributeNames()
1814:             * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double)
1815:             *         setDoubleAttribute(String, double)
1816:             * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int)
1817:             *         setIntAttribute(String, int)
1818:             * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object)
1819:             *         setAttribute(String, Object)
1820:             * @see nanoxml.XMLElement#getAttribute(java.lang.String)
1821:             *         getAttribute(String)
1822:             * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object)
1823:             *         getAttribute(String, Object)
1824:             * @see nanoxml.XMLElement#getAttribute(java.lang.String,
1825:             *                                      java.util.Hashtable,
1826:             *                                      java.lang.String, boolean)
1827:             *         getAttribute(String, Hashtable, String, boolean)
1828:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String)
1829:             *         getStringAttribute(String)
1830:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
1831:             *                                            java.lang.String)
1832:             *         getStringAttribute(String, String)
1833:             * @see nanoxml.XMLElement#getStringAttribute(java.lang.String,
1834:             *                                            java.util.Hashtable,
1835:             *                                            java.lang.String, boolean)
1836:             *         getStringAttribute(String, Hashtable, String, boolean)
1837:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String)
1838:             *         getIntAttribute(String)
1839:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int)
1840:             *         getIntAttribute(String, int)
1841:             * @see nanoxml.XMLElement#getIntAttribute(java.lang.String,
1842:             *                                         java.util.Hashtable,
1843:             *                                         java.lang.String, boolean)
1844:             *         getIntAttribute(String, Hashtable, String, boolean)
1845:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String)
1846:             *         getDoubleAttribute(String)
1847:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double)
1848:             *         getDoubleAttribute(String, double)
1849:             * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String,
1850:             *                                            java.util.Hashtable,
1851:             *                                            java.lang.String, boolean)
1852:             *         getDoubleAttribute(String, Hashtable, String, boolean)
1853:             * @see nanoxml.XMLElement#getBooleanAttribute(java.lang.String,
1854:             *                                             java.lang.String,
1855:             *                                             java.lang.String, boolean)
1856:             *         getBooleanAttribute(String, String, String, boolean)
1857:             */
1858:            public void removeAttribute(String name) {
1859:                if (this .ignoreCase) {
1860:                    name = name.toUpperCase();
1861:                }
1862:                this .attributes.remove(name);
1863:            }
1864:
1865:            /**
1866:             * Removes an attribute.
1867:             *
1868:             * @param name
1869:             *     The name of the attribute.
1870:             *
1871:             * @deprecated Use {@link #removeAttribute(java.lang.String)
1872:             *             removeAttribute} instead.
1873:             */
1874:            public void removeProperty(String name) {
1875:                this .removeAttribute(name);
1876:            }
1877:
1878:            /**
1879:             * Removes an attribute.
1880:             *
1881:             * @param name
1882:             *     The name of the attribute.
1883:             *
1884:             * @deprecated Use {@link #removeAttribute(java.lang.String)
1885:             *             removeAttribute} instead.
1886:             */
1887:            public void removeChild(String name) {
1888:                this .removeAttribute(name);
1889:            }
1890:
1891:            /**
1892:             * Creates a new similar XML element.
1893:             * <P>
1894:             * You should override this method when subclassing XMLElement.
1895:             */
1896:            protected XMLElement createAnotherElement() {
1897:                return new XMLElement(this .entities, this .ignoreWhitespace,
1898:                        false, this .ignoreCase);
1899:            }
1900:
1901:            /**
1902:             * Changes the content string.
1903:             *
1904:             * @param content
1905:             *     The new content string.
1906:             */
1907:            public void setContent(String content) {
1908:                this .contents = content;
1909:            }
1910:
1911:            /**
1912:             * Changes the name of the element.
1913:             *
1914:             * @param name
1915:             *     The new name.
1916:             *
1917:             * @deprecated Use {@link #setName(java.lang.String) setName} instead.
1918:             */
1919:            public void setTagName(String name) {
1920:                this .setName(name);
1921:            }
1922:
1923:            /**
1924:             * Changes the name of the element.
1925:             *
1926:             * @param name
1927:             *     The new name.
1928:             *
1929:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1930:             * <ul><li><code>name != null</code>
1931:             *     <li><code>name</code> is a valid XML identifier
1932:             * </ul></dd></dl>
1933:             *
1934:             * @see nanoxml.XMLElement#getName()
1935:             */
1936:            public void setName(String name) {
1937:                this .name = name;
1938:            }
1939:
1940:            /**
1941:             * Writes the XML element to a string.
1942:             *
1943:             * @see nanoxml.XMLElement#write(java.io.Writer) write(Writer)
1944:             */
1945:            public String toString() {
1946:                try {
1947:                    ByteArrayOutputStream out = new ByteArrayOutputStream();
1948:                    OutputStreamWriter writer = new OutputStreamWriter(out);
1949:                    this .write(writer);
1950:                    writer.flush();
1951:                    return new String(out.toByteArray());
1952:                } catch (IOException e) {
1953:                    // Java exception handling suxx
1954:                    return super .toString();
1955:                }
1956:            }
1957:
1958:            /**
1959:             * Writes the XML element to a writer.
1960:             *
1961:             * @param writer
1962:             *     The writer to write the XML data to.
1963:             *
1964:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
1965:             * <ul><li><code>writer != null</code>
1966:             *     <li><code>writer</code> is not closed
1967:             * </ul></dd></dl>
1968:             *
1969:             * @throws java.io.IOException
1970:             *      If the data could not be written to the writer.
1971:             *
1972:             * @see nanoxml.XMLElement#toString()
1973:             */
1974:            public void write(Writer writer)
1975:        throws IOException
1976:    {
1977:        if (this .name == null) {
1978:            this .writeEncoded(writer, this .contents);
1979:            return;
1980:        }
1981:        writer.write('<');
1982:        writer.write(this .name);
1983:        if (! this .attributes.isEmpty()) {
1984:            Enumeration enum = this .attributes.keys();
1985:            while (enum.hasMoreElements()) {
1986:                writer.write(' ');
1987:                String key = (String) enum.nextElement();
1988:                String value = (String) this .attributes.get(key);
1989:                writer.write(key);
1990:                writer.write('='); writer.write('"');
1991:                this .writeEncoded(writer, value);
1992:                writer.write('"');
1993:            }
1994:        }
1995:        if ((this .contents != null) && (this .contents.length() > 0)) {
1996:            writer.write('>');
1997:            this .writeEncoded(writer, this .contents);
1998:            writer.write('<'); writer.write('/');
1999:            writer.write(this .name);
2000:            writer.write('>');
2001:        } else if (this .children.isEmpty()) {
2002:            writer.write('/'); writer.write('>');
2003:        } else {
2004:            writer.write('>');
2005:            Enumeration enum = this .enumerateChildren();
2006:            while (enum.hasMoreElements()) {
2007:                XMLElement child = (XMLElement) enum.nextElement();
2008:                child.write(writer);
2009:            }
2010:            writer.write('<'); writer.write('/');
2011:            writer.write(this .name);
2012:            writer.write('>');
2013:        }
2014:    }
2015:
2016:            /**
2017:             * Writes a string encoded to a writer.
2018:             *
2019:             * @param writer
2020:             *     The writer to write the XML data to.
2021:             * @param str
2022:             *     The string to write encoded.
2023:             *
2024:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2025:             * <ul><li><code>writer != null</code>
2026:             *     <li><code>writer</code> is not closed
2027:             *     <li><code>str != null</code>
2028:             * </ul></dd></dl>
2029:             */
2030:            protected void writeEncoded(Writer writer, String str)
2031:                    throws IOException {
2032:                for (int i = 0; i < str.length(); i += 1) {
2033:                    char ch = str.charAt(i);
2034:                    switch (ch) {
2035:                    case '<':
2036:                        writer.write('&');
2037:                        writer.write('l');
2038:                        writer.write('t');
2039:                        writer.write(';');
2040:                        break;
2041:                    case '>':
2042:                        writer.write('&');
2043:                        writer.write('g');
2044:                        writer.write('t');
2045:                        writer.write(';');
2046:                        break;
2047:                    case '&':
2048:                        writer.write('&');
2049:                        writer.write('a');
2050:                        writer.write('m');
2051:                        writer.write('p');
2052:                        writer.write(';');
2053:                        break;
2054:                    case '"':
2055:                        writer.write('&');
2056:                        writer.write('q');
2057:                        writer.write('u');
2058:                        writer.write('o');
2059:                        writer.write('t');
2060:                        writer.write(';');
2061:                        break;
2062:                    case '\'':
2063:                        writer.write('&');
2064:                        writer.write('a');
2065:                        writer.write('p');
2066:                        writer.write('o');
2067:                        writer.write('s');
2068:                        writer.write(';');
2069:                        break;
2070:                    default:
2071:                        int unicode = (int) ch;
2072:                        if ((unicode < 32) || (unicode > 126)) {
2073:                            writer.write('&');
2074:                            writer.write('#');
2075:                            writer.write('x');
2076:                            writer.write(Integer.toString(unicode, 16));
2077:                            writer.write(';');
2078:                        } else {
2079:                            writer.write(ch);
2080:                        }
2081:                    }
2082:                }
2083:            }
2084:
2085:            /**
2086:             * Scans an identifier from the current reader.
2087:             * The scanned identifier is appended to <code>result</code>.
2088:             *
2089:             * @param result
2090:             *     The buffer in which the scanned identifier will be put.
2091:             *
2092:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2093:             * <ul><li><code>result != null</code>
2094:             *     <li>The next character read from the reader is a valid first
2095:             *         character of an XML identifier.
2096:             * </ul></dd></dl>
2097:             *
2098:             * <dl><dt><b>Postconditions:</b></dt><dd>
2099:             * <ul><li>The next character read from the reader won't be an identifier
2100:             *         character.
2101:             * </ul></dd></dl><dl>
2102:             */
2103:            protected void scanIdentifier(StringBuffer result)
2104:                    throws IOException {
2105:                for (;;) {
2106:                    char ch = this .readChar();
2107:                    if (((ch < 'A') || (ch > 'Z'))
2108:                            && ((ch < 'a') || (ch > 'z'))
2109:                            && ((ch < '0') || (ch > '9')) && (ch != '_')
2110:                            && (ch != '.') && (ch != ':') && (ch != '-')
2111:                            && (ch <= '\u007E')) {
2112:                        this .unreadChar(ch);
2113:                        return;
2114:                    }
2115:                    result.append(ch);
2116:                }
2117:            }
2118:
2119:            /**
2120:             * This method scans an identifier from the current reader.
2121:             *
2122:             * @return the next character following the whitespace.
2123:             */
2124:            protected char scanWhitespace() throws IOException {
2125:                for (;;) {
2126:                    char ch = this .readChar();
2127:                    switch (ch) {
2128:                    case ' ':
2129:                    case '\t':
2130:                    case '\n':
2131:                    case '\r':
2132:                        break;
2133:                    default:
2134:                        return ch;
2135:                    }
2136:                }
2137:            }
2138:
2139:            /**
2140:             * This method scans an identifier from the current reader.
2141:             * The scanned whitespace is appended to <code>result</code>.
2142:             *
2143:             * @return the next character following the whitespace.
2144:             *
2145:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2146:             * <ul><li><code>result != null</code>
2147:             * </ul></dd></dl>
2148:             */
2149:            protected char scanWhitespace(StringBuffer result)
2150:                    throws IOException {
2151:                for (;;) {
2152:                    char ch = this .readChar();
2153:                    switch (ch) {
2154:                    case ' ':
2155:                    case '\t':
2156:                    case '\n':
2157:                        result.append(ch);
2158:                    case '\r':
2159:                        break;
2160:                    default:
2161:                        return ch;
2162:                    }
2163:                }
2164:            }
2165:
2166:            /**
2167:             * This method scans a delimited string from the current reader.
2168:             * The scanned string without delimiters is appended to
2169:             * <code>string</code>.
2170:             *
2171:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2172:             * <ul><li><code>string != null</code>
2173:             *     <li>the next char read is the string delimiter
2174:             * </ul></dd></dl>
2175:             */
2176:            protected void scanString(StringBuffer string) throws IOException {
2177:                char delimiter = this .readChar();
2178:                if ((delimiter != '\'') && (delimiter != '"')) {
2179:                    throw this .expectedInput("' or \"");
2180:                }
2181:                for (;;) {
2182:                    char ch = this .readChar();
2183:                    if (ch == delimiter) {
2184:                        return;
2185:                    } else if (ch == '&') {
2186:                        this .resolveEntity(string);
2187:                    } else {
2188:                        string.append(ch);
2189:                    }
2190:                }
2191:            }
2192:
2193:            /**
2194:             * Scans a #PCDATA element. CDATA sections and entities are resolved.
2195:             * The next &lt; char is skipped.
2196:             * The scanned data is appended to <code>data</code>.
2197:             *
2198:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2199:             * <ul><li><code>data != null</code>
2200:             * </ul></dd></dl>
2201:             */
2202:            protected void scanPCData(StringBuffer data) throws IOException {
2203:                for (;;) {
2204:                    char ch = this .readChar();
2205:                    if (ch == '<') {
2206:                        ch = this .readChar();
2207:                        if (ch == '!') {
2208:                            this .checkCDATA(data);
2209:                        } else {
2210:                            this .unreadChar(ch);
2211:                            return;
2212:                        }
2213:                    } else if (ch == '&') {
2214:                        this .resolveEntity(data);
2215:                    } else {
2216:                        data.append(ch);
2217:                    }
2218:                }
2219:            }
2220:
2221:            /**
2222:             * Scans a special tag and if the tag is a CDATA section, append its
2223:             * content to <code>buf</code>.
2224:             *
2225:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2226:             * <ul><li><code>buf != null</code>
2227:             *     <li>The first &lt; has already been read.
2228:             * </ul></dd></dl>
2229:             */
2230:            protected boolean checkCDATA(StringBuffer buf) throws IOException {
2231:                char ch = this .readChar();
2232:                if (ch != '[') {
2233:                    this .unreadChar(ch);
2234:                    this .skipSpecialTag(0);
2235:                    return false;
2236:                } else if (!this .checkLiteral("CDATA[")) {
2237:                    this .skipSpecialTag(1); // one [ has already been read
2238:                    return false;
2239:                } else {
2240:                    int delimiterCharsSkipped = 0;
2241:                    while (delimiterCharsSkipped < 3) {
2242:                        ch = this .readChar();
2243:                        switch (ch) {
2244:                        case ']':
2245:                            if (delimiterCharsSkipped < 2) {
2246:                                delimiterCharsSkipped += 1;
2247:                            } else {
2248:                                buf.append(']');
2249:                                buf.append(']');
2250:                                delimiterCharsSkipped = 0;
2251:                            }
2252:                            break;
2253:                        case '>':
2254:                            if (delimiterCharsSkipped < 2) {
2255:                                for (int i = 0; i < delimiterCharsSkipped; i++) {
2256:                                    buf.append(']');
2257:                                }
2258:                                delimiterCharsSkipped = 0;
2259:                                buf.append('>');
2260:                            } else {
2261:                                delimiterCharsSkipped = 3;
2262:                            }
2263:                            break;
2264:                        default:
2265:                            for (int i = 0; i < delimiterCharsSkipped; i += 1) {
2266:                                buf.append(']');
2267:                            }
2268:                            buf.append(ch);
2269:                            delimiterCharsSkipped = 0;
2270:                        }
2271:                    }
2272:                    return true;
2273:                }
2274:            }
2275:
2276:            /**
2277:             * Skips a comment.
2278:             *
2279:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2280:             * <ul><li>The first &lt;!-- has already been read.
2281:             * </ul></dd></dl>
2282:             */
2283:            protected void skipComment() throws IOException {
2284:                int dashesToRead = 2;
2285:                while (dashesToRead > 0) {
2286:                    char ch = this .readChar();
2287:                    if (ch == '-') {
2288:                        dashesToRead -= 1;
2289:                    } else {
2290:                        dashesToRead = 2;
2291:                    }
2292:                }
2293:                if (this .readChar() != '>') {
2294:                    throw this .expectedInput(">");
2295:                }
2296:            }
2297:
2298:            /**
2299:             * Skips a special tag or comment.
2300:             *
2301:             * @param bracketLevel The number of open square brackets ([) that have
2302:             *                     already been read.
2303:             *
2304:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2305:             * <ul><li>The first &lt;! has already been read.
2306:             *     <li><code>bracketLevel >= 0</code>
2307:             * </ul></dd></dl>
2308:             */
2309:            protected void skipSpecialTag(int bracketLevel) throws IOException {
2310:                int tagLevel = 1; // <
2311:                char stringDelimiter = '\0';
2312:                if (bracketLevel == 0) {
2313:                    char ch = this .readChar();
2314:                    if (ch == '[') {
2315:                        bracketLevel += 1;
2316:                    } else if (ch == '-') {
2317:                        ch = this .readChar();
2318:                        if (ch == '[') {
2319:                            bracketLevel += 1;
2320:                        } else if (ch == ']') {
2321:                            bracketLevel -= 1;
2322:                        } else if (ch == '-') {
2323:                            this .skipComment();
2324:                            return;
2325:                        }
2326:                    }
2327:                }
2328:                while (tagLevel > 0) {
2329:                    char ch = this .readChar();
2330:                    if (stringDelimiter == '\0') {
2331:                        if ((ch == '"') || (ch == '\'')) {
2332:                            stringDelimiter = ch;
2333:                        } else if (bracketLevel <= 0) {
2334:                            if (ch == '<') {
2335:                                tagLevel += 1;
2336:                            } else if (ch == '>') {
2337:                                tagLevel -= 1;
2338:                            }
2339:                        }
2340:                        if (ch == '[') {
2341:                            bracketLevel += 1;
2342:                        } else if (ch == ']') {
2343:                            bracketLevel -= 1;
2344:                        }
2345:                    } else {
2346:                        if (ch == stringDelimiter) {
2347:                            stringDelimiter = '\0';
2348:                        }
2349:                    }
2350:                }
2351:            }
2352:
2353:            /**
2354:             * Scans the data for literal text.
2355:             * Scanning stops when a character does not match or after the complete
2356:             * text has been checked, whichever comes first.
2357:             *
2358:             * @param literal the literal to check.
2359:             *
2360:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2361:             * <ul><li><code>literal != null</code>
2362:             * </ul></dd></dl>
2363:             */
2364:            protected boolean checkLiteral(String literal) throws IOException {
2365:                int length = literal.length();
2366:                for (int i = 0; i < length; i += 1) {
2367:                    if (this .readChar() != literal.charAt(i)) {
2368:                        return false;
2369:                    }
2370:                }
2371:                return true;
2372:            }
2373:
2374:            /**
2375:             * Reads a character from a reader.
2376:             */
2377:            protected char readChar() throws IOException {
2378:                if (this .charReadTooMuch != '\0') {
2379:                    char ch = this .charReadTooMuch;
2380:                    this .charReadTooMuch = '\0';
2381:                    return ch;
2382:                } else {
2383:                    int i = this .reader.read();
2384:                    if (i < 0) {
2385:                        throw this .unexpectedEndOfData();
2386:                    } else if (i == 10) {
2387:                        this .parserLineNr += 1;
2388:                        return '\n';
2389:                    } else {
2390:                        return (char) i;
2391:                    }
2392:                }
2393:            }
2394:
2395:            /**
2396:             * Scans an XML element.
2397:             *
2398:             * @param elt The element that will contain the result.
2399:             *
2400:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2401:             * <ul><li>The first &lt; has already been read.
2402:             *     <li><code>elt != null</code>
2403:             * </ul></dd></dl>
2404:             */
2405:            protected void scanElement(XMLElement elt) throws IOException {
2406:                StringBuffer buf = new StringBuffer();
2407:                this .scanIdentifier(buf);
2408:                String name = buf.toString();
2409:                elt.setName(name);
2410:                char ch = this .scanWhitespace();
2411:                while ((ch != '>') && (ch != '/')) {
2412:                    buf.setLength(0);
2413:                    this .unreadChar(ch);
2414:                    this .scanIdentifier(buf);
2415:                    String key = buf.toString();
2416:                    ch = this .scanWhitespace();
2417:                    if (ch != '=') {
2418:                        throw this .expectedInput("=");
2419:                    }
2420:                    this .unreadChar(this .scanWhitespace());
2421:                    buf.setLength(0);
2422:                    this .scanString(buf);
2423:                    elt.setAttribute(key, buf);
2424:                    ch = this .scanWhitespace();
2425:                }
2426:                if (ch == '/') {
2427:                    ch = this .readChar();
2428:                    if (ch != '>') {
2429:                        throw this .expectedInput(">");
2430:                    }
2431:                    return;
2432:                }
2433:                buf.setLength(0);
2434:                ch = this .scanWhitespace(buf);
2435:                if (ch != '<') {
2436:                    this .unreadChar(ch);
2437:                    this .scanPCData(buf);
2438:                } else {
2439:                    for (;;) {
2440:                        ch = this .readChar();
2441:                        if (ch == '!') {
2442:                            if (this .checkCDATA(buf)) {
2443:                                this .scanPCData(buf);
2444:                                break;
2445:                            } else {
2446:                                ch = this .scanWhitespace(buf);
2447:                                if (ch != '<') {
2448:                                    this .unreadChar(ch);
2449:                                    this .scanPCData(buf);
2450:                                    break;
2451:                                }
2452:                            }
2453:                        } else {
2454:                            if ((ch != '/') || this .ignoreWhitespace) {
2455:                                buf.setLength(0);
2456:                            }
2457:                            if (ch == '/') {
2458:                                this .unreadChar(ch);
2459:                            }
2460:                            break;
2461:                        }
2462:                    }
2463:                }
2464:                if (buf.length() == 0) {
2465:                    while (ch != '/') {
2466:                        if (ch == '!') {
2467:                            ch = this .readChar();
2468:                            if (ch != '-') {
2469:                                throw this .expectedInput("Comment or Element");
2470:                            }
2471:                            ch = this .readChar();
2472:                            if (ch != '-') {
2473:                                throw this .expectedInput("Comment or Element");
2474:                            }
2475:                            this .skipComment();
2476:                        } else {
2477:                            this .unreadChar(ch);
2478:                            XMLElement child = this .createAnotherElement();
2479:                            this .scanElement(child);
2480:                            elt.addChild(child);
2481:                        }
2482:                        ch = this .scanWhitespace();
2483:                        if (ch != '<') {
2484:                            throw this .expectedInput("<");
2485:                        }
2486:                        ch = this .readChar();
2487:                    }
2488:                    this .unreadChar(ch);
2489:                } else {
2490:                    if (this .ignoreWhitespace) {
2491:                        elt.setContent(buf.toString().trim());
2492:                    } else {
2493:                        elt.setContent(buf.toString());
2494:                    }
2495:                }
2496:                ch = this .readChar();
2497:                if (ch != '/') {
2498:                    throw this .expectedInput("/");
2499:                }
2500:                this .unreadChar(this .scanWhitespace());
2501:                if (!this .checkLiteral(name)) {
2502:                    throw this .expectedInput(name);
2503:                }
2504:                if (this .scanWhitespace() != '>') {
2505:                    throw this .expectedInput(">");
2506:                }
2507:            }
2508:
2509:            /**
2510:             * Resolves an entity. The name of the entity is read from the reader.
2511:             * The value of the entity is appended to <code>buf</code>.
2512:             *
2513:             * @param buf Where to put the entity value.
2514:             *
2515:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2516:             * <ul><li>The first &amp; has already been read.
2517:             *     <li><code>buf != null</code>
2518:             * </ul></dd></dl>
2519:             */
2520:            protected void resolveEntity(StringBuffer buf) throws IOException {
2521:                char ch = '\0';
2522:                StringBuffer keyBuf = new StringBuffer();
2523:                for (;;) {
2524:                    ch = this .readChar();
2525:                    if (ch == ';') {
2526:                        break;
2527:                    }
2528:                    keyBuf.append(ch);
2529:                }
2530:                String key = keyBuf.toString();
2531:                if (key.charAt(0) == '#') {
2532:                    try {
2533:                        if (key.charAt(1) == 'x') {
2534:                            ch = (char) Integer.parseInt(key.substring(2), 16);
2535:                        } else {
2536:                            ch = (char) Integer.parseInt(key.substring(1), 10);
2537:                        }
2538:                    } catch (NumberFormatException e) {
2539:                        throw this .unknownEntity(key);
2540:                    }
2541:                    buf.append(ch);
2542:                } else {
2543:                    char[] value = (char[]) this .entities.get(key);
2544:                    if (value == null) {
2545:                        throw this .unknownEntity(key);
2546:                    }
2547:                    buf.append(value);
2548:                }
2549:            }
2550:
2551:            /**
2552:             * Pushes a character back to the read-back buffer.
2553:             *
2554:             * @param ch The character to push back.
2555:             *
2556:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2557:             * <ul><li>The read-back buffer is empty.
2558:             *     <li><code>ch != '\0'</code>
2559:             * </ul></dd></dl>
2560:             */
2561:            protected void unreadChar(char ch) {
2562:                this .charReadTooMuch = ch;
2563:            }
2564:
2565:            /**
2566:             * Creates a parse exception for when an invalid valueset is given to
2567:             * a method.
2568:             *
2569:             * @param name The name of the entity.
2570:             *
2571:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2572:             * <ul><li><code>name != null</code>
2573:             * </ul></dd></dl>
2574:             */
2575:            protected XMLParseException invalidValueSet(String name) {
2576:                String msg = "Invalid value set (entity name = \"" + name
2577:                        + "\")";
2578:                return new XMLParseException(this .getName(), this .parserLineNr,
2579:                        msg);
2580:            }
2581:
2582:            /**
2583:             * Creates a parse exception for when an invalid value is given to a
2584:             * method.
2585:             *
2586:             * @param name  The name of the entity.
2587:             * @param value The value of the entity.
2588:             *
2589:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2590:             * <ul><li><code>name != null</code>
2591:             *     <li><code>value != null</code>
2592:             * </ul></dd></dl>
2593:             */
2594:            protected XMLParseException invalidValue(String name, String value) {
2595:                String msg = "Attribute \"" + name
2596:                        + "\" does not contain a valid " + "value (\"" + value
2597:                        + "\")";
2598:                return new XMLParseException(this .getName(), this .parserLineNr,
2599:                        msg);
2600:            }
2601:
2602:            /**
2603:             * Creates a parse exception for when the end of the data input has been
2604:             * reached.
2605:             */
2606:            protected XMLParseException unexpectedEndOfData() {
2607:                String msg = "Unexpected end of data reached";
2608:                return new XMLParseException(this .getName(), this .parserLineNr,
2609:                        msg);
2610:            }
2611:
2612:            /**
2613:             * Creates a parse exception for when a syntax error occured.
2614:             *
2615:             * @param context The context in which the error occured.
2616:             *
2617:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2618:             * <ul><li><code>context != null</code>
2619:             *     <li><code>context.length() &gt; 0</code>
2620:             * </ul></dd></dl>
2621:             */
2622:            protected XMLParseException syntaxError(String context) {
2623:                String msg = "Syntax error while parsing " + context;
2624:                return new XMLParseException(this .getName(), this .parserLineNr,
2625:                        msg);
2626:            }
2627:
2628:            /**
2629:             * Creates a parse exception for when the next character read is not
2630:             * the character that was expected.
2631:             *
2632:             * @param charSet The set of characters (in human readable form) that was
2633:             *                expected.
2634:             *
2635:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2636:             * <ul><li><code>charSet != null</code>
2637:             *     <li><code>charSet.length() &gt; 0</code>
2638:             * </ul></dd></dl>
2639:             */
2640:            protected XMLParseException expectedInput(String charSet) {
2641:                String msg = "Expected: " + charSet;
2642:                return new XMLParseException(this .getName(), this .parserLineNr,
2643:                        msg);
2644:            }
2645:
2646:            /**
2647:             * Creates a parse exception for when an entity could not be resolved.
2648:             *
2649:             * @param name The name of the entity.
2650:             *
2651:             * </dl><dl><dt><b>Preconditions:</b></dt><dd>
2652:             * <ul><li><code>name != null</code>
2653:             *     <li><code>name.length() &gt; 0</code>
2654:             * </ul></dd></dl>
2655:             */
2656:            protected XMLParseException unknownEntity(String name) {
2657:                String msg = "Unknown or invalid entity: &" + name + ";";
2658:                return new XMLParseException(this.getName(), this.parserLineNr,
2659:                        msg);
2660:            }
2661:
2662:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.