001// DtdDemo.java: demonstration application showing DTD queries. 002// NO WARRANTY! See README, and copyright below. 003// $Id$ 004// Modified 11/8/98 to add package statement. 005package com.microstar.xml.demo; 006 007import java.util.Enumeration; 008 009import com.microstar.xml.XmlParser; 010 011/** 012 * Demonstration application showing DTD queries. 013 * <p>Usage: <code>java DtdDemo <url></code> 014 * <p>Or, use it as an applet, supplying the URL as the <code>url</code> 015 * parameter. 016 * <p>Note: This does not preserve any processing instructions 017 * or parameter entities in the DTD; otherwise, produces a fully expanded 018 * and normalised version. 019 * @author Copyright (c) 1997, 1998 by Microstar Software Ltd.; 020 * @author written by David Megginson <dmeggins@microstar.com> 021 * @version 1.1 022 * @since Ptolemy II 0.2 023 * @see com.microstar.xml.XmlParser 024 * @see com.microstar.xml.XmlHandler 025 * @see XmlApp 026 */ 027public class DtdDemo extends XmlApp { 028 /** 029 * Entry point for an application (applets enter through XmlApp.init()). 030 * @param args The arguments. The first argument should be the uri 031 * @exception Exception If the parse fails 032 * @see XmlApp 033 */ 034 public static void main(String[] args) throws Exception { 035 DtdDemo demo = new DtdDemo(); 036 037 if (args.length != 1) { 038 System.err.println("Usage: java DtdDemo <uri>"); 039 System.exit(1); 040 } else { 041 demo.doParse(args[0]); 042 } 043 } 044 045 /** 046 * Print a comment showing where the DTD (if any) begins. 047 */ 048 @Override 049 public void startDocument() { 050 displayText("<-- Start of DTD -->\n"); 051 } 052 053 /** 054 * Print a comment showing where the DTD (if any) ends. 055 * @param errorCount Ignored in this method. 056 */ 057 public void endDocument(int errorCount) { 058 displayText("<-- End of DTD -->"); 059 } 060 061 /** 062 * Dump the DTD. 063 * <p>Once this event is received, we know that the DTD is 064 * completely parsed, and can use AElfred's query routines 065 * to reconstruct a normalised version of it. 066 * @see #dumpNotations 067 * @see #dumpEntities 068 * @see #dumpElements 069 */ 070 @Override 071 public void doctypeDecl(String name, String pubid, String sysid) { 072 dumpNotations(); 073 dumpEntities(); 074 dumpElements(); 075 } 076 077 /** 078 * Produce normalised declarations for all notations. 079 * @see #makeExternalIdentifiers 080 */ 081 public void dumpNotations() { 082 Enumeration notationNames = parser.declaredNotations(); 083 String nname; 084 String extId; 085 086 // Mark the beginning of a new section. 087 displayText("<-- Notation Declarations -->\n"); 088 089 // Loop through all declared notations. 090 while (notationNames.hasMoreElements()) { 091 nname = (String) notationNames.nextElement(); 092 extId = makeExternalIdentifiers(parser.getNotationPublicId(nname), 093 parser.getNotationSystemId(nname)); 094 displayText("<!NOTATION " + nname + +' ' + extId + ">\n"); 095 } 096 } 097 098 /** 099 * Produce normalised declarations for all general entities. 100 * @see #makeLiteral 101 * @see #makeExternalIdentifiers 102 */ 103 public void dumpEntities() { 104 Enumeration entityNames = parser.declaredEntities(); 105 String ename; 106 String value; 107 108 // Mark the beginning of a new section. 109 displayText("<-- Entity Declarations -->\n"); 110 111 // Loop through all the declared 112 // entities. 113 while (entityNames.hasMoreElements()) { 114 ename = (String) entityNames.nextElement(); 115 116 // Skip parameter entities. 117 if (ename.startsWith("%")) { 118 continue; 119 } 120 121 // Construct a value based on the 122 // class of entity. 123 value = null; 124 125 switch (parser.getEntityType(ename)) { 126 // Internal text entity 127 case XmlParser.ENTITY_INTERNAL: 128 value = makeLiteral(parser.getEntityValue(ename)); 129 break; 130 131 // External binary entity 132 case XmlParser.ENTITY_NDATA: 133 value = makeExternalIdentifiers(parser.getEntityPublicId(ename), 134 parser.getEntitySystemId(ename)) + "NDATA " 135 + parser.getEntityNotationName(ename); 136 break; 137 138 // External text entity 139 case XmlParser.ENTITY_TEXT: 140 value = makeExternalIdentifiers(parser.getEntityPublicId(ename), 141 parser.getEntitySystemId(ename)); 142 break; 143 } 144 145 // Print a normalised declaration. 146 displayText("<!ENTITY " + ename + ' ' + value + ">\n"); 147 } 148 } 149 150 /** 151 * Produce normalised declarations for all elements. 152 * @see #dumpAttributes 153 */ 154 public void dumpElements() { 155 Enumeration elementNames = parser.declaredElements(); 156 String elname; 157 158 // Mark the beginning of a new section. 159 displayText("<-- Element Type Declarations -->\n"); 160 161 // Loop through all of the declared 162 // elements. 163 while (elementNames.hasMoreElements()) { 164 String contentSpec = "ANY"; 165 166 elname = (String) elementNames.nextElement(); 167 168 // Construct a content spec based 169 // on the element's content type. 170 switch (parser.getElementContentType(elname)) { 171 case XmlParser.CONTENT_EMPTY: 172 contentSpec = "EMPTY"; 173 break; 174 175 case XmlParser.CONTENT_ANY: 176 contentSpec = "ANY"; 177 break; 178 179 case XmlParser.CONTENT_ELEMENTS: 180 case XmlParser.CONTENT_MIXED: 181 contentSpec = parser.getElementContentModel(elname); 182 break; 183 } 184 185 // Print a normalised element type 186 // declaration. 187 displayText("<!ELEMENT " + elname + ' ' + contentSpec + ">"); 188 189 // Print the ATTLIST declaration, 190 // if any. 191 dumpAttributes(elname); 192 193 // Blank line. 194 displayText(""); 195 } 196 } 197 198 /** 199 * Dump attributes for an element. 200 * @param elname The element name. 201 * @see #makeAttributeType 202 * @see #makeAttributeValue 203 */ 204 public void dumpAttributes(String elname) { 205 Enumeration attributeNames = parser.declaredAttributes(elname); 206 String aname; 207 String type; 208 String value; 209 210 // Skip if there are no declared 211 // attributes for this element 212 // type. 213 if (attributeNames == null) { 214 return; 215 } 216 217 // Print the start of the ATTLIST 218 // declaration. 219 displayText("<!ATTLIST " + elname); 220 221 // Loop through all of the declared 222 // attributes. 223 while (attributeNames.hasMoreElements()) { 224 aname = (String) attributeNames.nextElement(); 225 type = makeAttributeType(elname, aname); 226 value = makeAttributeValue(elname, aname); 227 228 // Print the declaration for a 229 // single attribute. 230 displayText(" " + aname + ' ' + type + ' ' + value); 231 } 232 233 // Finish the ATTLIST declaration. 234 displayText(">"); 235 } 236 237 /** 238 * Generate the attribute type as a normalised string. 239 * @param elname The element name. 240 * @param aname The attribute name. 241 * @return The attribute type as a normalised string. 242 */ 243 public String makeAttributeType(String elname, String aname) { 244 // Construct a string equivalent 245 // of the attribute type. 246 switch (parser.getAttributeType(elname, aname)) { 247 case XmlParser.ATTRIBUTE_CDATA: 248 return "CDATA"; 249 250 case XmlParser.ATTRIBUTE_ID: 251 return "ID"; 252 253 case XmlParser.ATTRIBUTE_IDREF: 254 return "IDREF"; 255 256 case XmlParser.ATTRIBUTE_IDREFS: 257 return "IDREFS"; 258 259 case XmlParser.ATTRIBUTE_ENTITY: 260 return "ENTITY"; 261 262 case XmlParser.ATTRIBUTE_ENTITIES: 263 return "ENTITIES"; 264 265 case XmlParser.ATTRIBUTE_NMTOKEN: 266 return "NMTOKEN"; 267 268 case XmlParser.ATTRIBUTE_NMTOKENS: 269 return "NMTOKENS"; 270 271 case XmlParser.ATTRIBUTE_ENUMERATED: 272 273 // An enumeration. 274 return parser.getAttributeEnumeration(elname, aname); 275 276 case XmlParser.ATTRIBUTE_NOTATION: 277 278 // An enumeration of notations. 279 return "NOTATION " + parser.getAttributeEnumeration(elname, aname); 280 } 281 282 return null; 283 } 284 285 /** 286 * Generate a full attribute default value. 287 * @param elname The element name. 288 * @param aname The attribute name. 289 * @return The full attribute default value 290 * @see #makeLiteral 291 */ 292 public String makeAttributeValue(String elname, String aname) { 293 // Generate a default value based 294 // on the type. 295 switch (parser.getAttributeDefaultValueType(elname, aname)) { 296 case XmlParser.ATTRIBUTE_DEFAULT_IMPLIED: 297 return "#IMPLIED"; 298 299 case XmlParser.ATTRIBUTE_DEFAULT_SPECIFIED: 300 return makeLiteral(parser.getAttributeDefaultValue(elname, aname)); 301 302 case XmlParser.ATTRIBUTE_DEFAULT_REQUIRED: 303 return "#REQUIRED"; 304 305 case XmlParser.ATTRIBUTE_DEFAULT_FIXED: 306 return "#FIXED " + makeLiteral( 307 parser.getAttributeDefaultValue(elname, aname)); 308 } 309 310 return null; 311 } 312 313 /** 314 * Construct a string equivalent of external identifiers. 315 * @param pubid The public identifier 316 * @param sysid The string id 317 * @return The external identifiers 318 * @see #makeLiteral 319 */ 320 public String makeExternalIdentifiers(String pubid, String sysid) { 321 String extId = ""; 322 323 if (pubid != null) { 324 extId = "PUBLIC " + makeLiteral(pubid); 325 326 if (sysid != null) { 327 extId = extId + ' ' + makeLiteral(sysid); 328 } 329 } else { 330 extId = "SYSTEM " + makeLiteral(sysid); 331 } 332 333 return extId; 334 } 335 336 /** 337 * Quote a literal, and escape any '"' or non-ASCII characters within it. 338 * @param data The data 339 * @return the data as a literal 340 */ 341 public String makeLiteral(String data) { 342 char[] ch = data.toCharArray(); 343 StringBuffer buf = new StringBuffer(); 344 345 buf.append('"'); 346 347 for (char element : ch) { 348 if (element == '"') { 349 buf.append(""); 350 } else if (element > 0x7f) { 351 buf.append("&#" + (int) element + ";"); 352 } else { 353 buf.append(element); 354 } 355 } 356 357 buf.append('"'); 358 359 return buf.toString(); 360 } 361} 362 363// End of DtdDemo.java