0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.tax.io;
0043:
0044: import java.io.*;
0045: import java.net.URL;
0046: import java.util.*;
0047: import java.text.MessageFormat;
0048: import java.lang.reflect.*;
0049:
0050: import org.xml.sax.*;
0051: import org.xml.sax.helpers.LocatorImpl;
0052:
0053: import org.apache.xerces.xni.*;
0054: import org.apache.xerces.xni.parser.XMLDTDSource;
0055: import org.apache.xerces.xni.parser.XMLDTDContentModelSource;
0056: import org.apache.xerces.xni.parser.XMLDocumentSource;
0057: import org.apache.xerces.parsers.*;
0058:
0059: import org.netbeans.tax.*;
0060: import org.netbeans.tax.io.*;
0061: import org.netbeans.tax.decl.*;
0062: import java.util.List;
0063:
0064: /**
0065: * Xerces Native Interface ("XNI") based implementation. It sets
0066: * namespace non-aware and non-validating features.
0067: * <p>
0068: * Do instantiate it directly, prefer TreeBuilder interface loaded by TreeStreamSource
0069: * (i.e. ParserLoader). It will do necessary implementation isolation.
0070: * <p>
0071: * Every well-formed source must be possible to convert to tree structure.
0072: * //!!! A mechanism of supressing particular implemenation constrains will
0073: * be needed (JAXP validation on request could be a good approach).
0074: *
0075: * @author Petr Kuzel
0076: * @version rewritten to XNI 2.4.0
0077: */
0078: public final class XNIBuilder implements TreeBuilder {
0079:
0080: private static final boolean ASSERT = false;
0081:
0082: // private static final PrintStream dbg = System.err;
0083:
0084: private static final String DTD_WRAPPER = "<!DOCTYPE DTD PUBLIC \"{0}\" \"{1}\">"; // NOI18N
0085:
0086: // TreeStreamSource defines
0087: private Class buildClass; //DTD or XML [or Fragment]
0088:
0089: private InputSource inputSource;
0090:
0091: // interface for reporting errors during the tree construction
0092: private TreeStreamBuilderErrorHandler errorHandler;
0093:
0094: // do not forget to set to the parser
0095: private EntityResolver entityResolver;
0096:
0097: /** Creates new TreeStreamBuilderXercesImpl */
0098: public XNIBuilder(Class buildClass, InputSource inputSource,
0099: EntityResolver entityResolver,
0100: TreeStreamBuilderErrorHandler errorHandler) {
0101: init(buildClass, inputSource, entityResolver, errorHandler);
0102: }
0103:
0104: /** Initialize it */
0105: private void init(Class buildClass, InputSource inputSource,
0106: EntityResolver entityResolver,
0107: TreeStreamBuilderErrorHandler errorHandler) {
0108: this .inputSource = inputSource;
0109: this .buildClass = buildClass;
0110: this .errorHandler = errorHandler;
0111: this .entityResolver = entityResolver;
0112: }
0113:
0114: /**
0115: * Build new TreeDocument by delegating to private class (hiding its
0116: * public XNI interfaces implementation).
0117: */
0118: public TreeDocumentRoot buildDocument() throws TreeException {
0119:
0120: boolean buildXML = true;
0121: InputSource builderSource = inputSource;
0122: EntityResolver builderResolver = entityResolver;
0123:
0124: /*
0125: * We are building DTD so wrap into auxiliary InputSource that
0126: * can be passed to XML parser.
0127: */
0128: if (buildClass == TreeDTD.class) {
0129:
0130: String src = MessageFormat.format(DTD_WRAPPER,
0131: new Object[] { DTDEntityResolver.DTD_ID,
0132: inputSource.getSystemId() });
0133:
0134: builderSource = new InputSource(inputSource.getSystemId());
0135: builderSource.setCharacterStream(new StringReader(src));
0136:
0137: builderResolver = new DTDEntityResolver();
0138: buildXML = false;
0139: }
0140:
0141: XMLBuilder builder = this .new XMLBuilder(buildXML);
0142:
0143: try {
0144: final String SAX_FEATURE = "http://xml.org/sax/features/"; // NOI18N
0145: final String XERCES_FEATURE = "http://apache.org/xml/features/"; // NOI18N
0146:
0147: builder.setFeature(SAX_FEATURE + "namespaces", false); //!!! // NOI18N
0148: builder.setFeature(SAX_FEATURE + "validation", false); //!!! // NOI18N
0149: builder.setFeature(SAX_FEATURE
0150: + "external-general-entities", true); // NOI18N
0151: builder.setFeature(SAX_FEATURE
0152: + "external-parameter-entities", true); // NOI18N
0153: builder.setFeature(XERCES_FEATURE
0154: + "validation/warn-on-duplicate-attdef", true); // NOI18N
0155: // unrecognized in Xerces 2.4.0
0156: //builder.setFeature (XERCES_FEATURE + "validation/warn-on-undeclared-elemdef", true); // NOI18N
0157: builder.setFeature(XERCES_FEATURE + "allow-java-encodings",
0158: true); // NOI18N
0159: builder.setFeature(XERCES_FEATURE
0160: + "scanner/notify-char-refs", true); // NOI18N
0161: builder.setFeature(XERCES_FEATURE
0162: + "scanner/notify-builtin-refs", true); // NOI18N
0163:
0164: // final String XERCES_PROPERTY = "http://apache.org/xml/properties/"; // NOI18N
0165: // builder.setProperty(XERCES_PROPERTY + "internal/entity-resolver", builderResolver); // NOI18N
0166:
0167: builder.setEntityResolver(builderResolver);
0168:
0169: // the builder extends XNIDocumentParser that receives
0170: // error events directly
0171:
0172: builder.setErrorHandler(new ErrorHandler() {
0173: public void error(org.xml.sax.SAXParseException e) {
0174: }
0175:
0176: public void warning(org.xml.sax.SAXParseException e) {
0177: }
0178:
0179: public void fatalError(org.xml.sax.SAXParseException e) {
0180: }
0181: });
0182: builder.parse(builderSource);
0183:
0184: } catch (DTDStopException stop) {
0185:
0186: // we just stopped the parser at the end of standalone DTD
0187:
0188: } catch (SAXException sax) {
0189:
0190: // test whether wrapped exception is XNI one
0191: // if so it wrrap actual exception
0192:
0193: Exception exception = sax.getException();
0194:
0195: if ((exception instanceof DTDStopException) == false) {
0196:
0197: if (Util.THIS.isLoggable()) /* then */
0198: Util.THIS.debug("sax", sax); // NOI18N
0199: if (Util.THIS.isLoggable()) /* then */
0200: Util.THIS.debug("exception", exception); // NOI18N
0201:
0202: if (exception instanceof XNIException) {
0203: exception = ((XNIException) exception)
0204: .getException();
0205: }
0206: if (exception != null) {
0207: if (!!!(exception instanceof TreeException)) {
0208: exception = new TreeException(sax);
0209: }
0210: } else {
0211: exception = new TreeException(sax);
0212: }
0213: throw (TreeException) exception;
0214: }
0215:
0216: } catch (IOException exc) {
0217: if (Util.THIS.isLoggable()) /* then */
0218: Util.THIS.debug("exc", exc); // NOI18N
0219:
0220: throw new TreeException(exc);
0221: }
0222:
0223: return builder.getDocumentRoot();
0224: }
0225:
0226: /*
0227: * Resolve DTD to original InputSource, forward others.
0228: * DTD builder uses wrapping InputSource so XML parser can be used as DTD one.
0229: */
0230: private class DTDEntityResolver implements EntityResolver {
0231:
0232: static final String DTD_ID = "PRIVATE//AUXILIARY DTD ID//PRIVATE"; // NOI18N
0233:
0234: public InputSource resolveEntity(String publicId,
0235: String systemId) throws SAXException, IOException {
0236:
0237: if (DTD_ID.equals(publicId)) {
0238: return inputSource;
0239: } else {
0240: return entityResolver.resolveEntity(publicId, systemId);
0241: }
0242: }
0243:
0244: }
0245:
0246: /*
0247: * It is used to signal that we are parsing a DTD and we reached end of it.
0248: * So we can stop the parser by throwing it.
0249: */
0250: private class DTDStopException extends XNIException {
0251:
0252: /** Serial Version UID */
0253: private static final long serialVersionUID = 4994054007367982021L;
0254:
0255: public DTDStopException() {
0256: super ("This exception is used to signal end of DTD."); // NOI18N
0257: };
0258:
0259: //
0260: // Look like wrapping exception, so it be converted so SAXException
0261: // that wraps this one.
0262: //
0263: public Exception getException() {
0264: return this ;
0265: }
0266:
0267: public Throwable fillInStackTrace() {
0268: return this ;
0269: }
0270: }
0271:
0272: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0273:
0274: /*
0275: * A pipeline of document components starts with a document source; is
0276: * followed by zero or more document filters; and ends with a document
0277: * handler.
0278: *
0279: * The document handler follows.
0280: */
0281:
0282: /**
0283: * Listens on XNI creating XML structure. It uses mini XNI pipe
0284: * featuring just with scanner. A validator is used but validity
0285: * are discarded since tree must be just well-formed ("WF").
0286: */
0287: private class XMLBuilder extends SAXParser implements
0288: XMLDTDContentModelHandler, XMLDocumentHandler,
0289: XMLDTDHandler {
0290:
0291: private TreeDocumentRoot returnDocument; // initial parent
0292: private TreeDocumentRoot document; // tmp variable
0293:
0294: private TreeDocumentType doctype; // it will become parent node of DTD content
0295: private TreeNode tempNode; // current working node
0296:
0297: private Stack parentObjectListStack; // parents' child lists stack
0298: private TreeObjectList parentObjectList; // top of the stack
0299: private Stack parentNodeStack; // some times we need nodes directly
0300:
0301: private Stack elementStack; // ??? it could be avoided
0302: private int entityCounter; // how deep we entered
0303:
0304: private boolean isXMLDocument; // do we parser XML or standalone DTD
0305: private boolean inCDATASection; // we are in the middle of CDATA
0306: private boolean inDTD; // we are in DTD
0307: private boolean isCorrect; // builder internal error
0308: private boolean inCharacterRef; //
0309:
0310: private StringBuffer cdataSectionBuffer; // working CDATA section buffer
0311: private QName tmpQName = new QName(); // working Qname
0312: private TreeAttlistDecl attlistDecl = null; // latest attlistdecl
0313:
0314: private int errors = 0; // fatal error counter
0315:
0316: private final String XML_ENTITY = "[xml]"; // name of entity that precedes startDocument call // NOI18N
0317: private final String DTD_ENTITY = "[dtd]"; // external DTD entity name // NOI18N
0318:
0319: private XMLLocator locator;
0320:
0321: private boolean hasExternalDTD = false;
0322:
0323: private RememberingReader rememberingReader;
0324:
0325: private XMLDTDSource xmldtdSource; // XMLDTDHandler 2.4.0
0326:
0327: private XMLDTDContentModelSource xmldtdContentModelSource; // XMLDTDContentModelHandler 2.4.0
0328:
0329: private XMLDocumentSource xmlDocumentSource; // XMLDocumentHanlder 2.4.0
0330:
0331: /**
0332: * Create a parser with standard configuration.
0333: * @param xmlDocument false if building standalone DTD
0334: */
0335: public XMLBuilder(boolean xmlDocument) {
0336: isXMLDocument = xmlDocument;
0337: entityCounter = 0;
0338: isCorrect = false;
0339: inCDATASection = false;
0340: inDTD = false;
0341: parentObjectListStack = new Stack();
0342: parentNodeStack = new Stack();
0343: elementStack = new Stack(); //stacks all non-empty elements
0344: cdataSectionBuffer = new StringBuffer();
0345: inCharacterRef = false;
0346: }
0347:
0348: /**
0349: * Sample user reader replacing it by remebering one suitable for
0350: * internal DTD remebering.
0351: */
0352: public void parse(InputSource in) throws IOException,
0353: SAXException {
0354: Reader reader = in.getCharacterStream();
0355: if (reader != null) {
0356: rememberingReader = new RememberingReader(reader);
0357: in.setCharacterStream(rememberingReader);
0358: rememberingReader.startRemembering(); //remember internal DTD see startElement for end
0359: }
0360:
0361: super .parse(in);
0362: }
0363:
0364: //
0365: // XMLDocumentHandler methods
0366: //
0367:
0368: public XMLDocumentSource getDocumentSource() {
0369: return xmlDocumentSource;
0370: }
0371:
0372: public void setDocumentSource(XMLDocumentSource src) {
0373: xmlDocumentSource = src;
0374: }
0375:
0376: // XMLDocumentHandler 2.4.0
0377: public void startDocument(XMLLocator locator, String encoding,
0378: NamespaceContext nsCtx, Augmentations a) {
0379: startDocument(locator, encoding, a);
0380: }
0381:
0382: /**
0383: * The start of the document.
0384: *
0385: * @throws SAXException Thrown by handler to signal an error.
0386: */
0387: // XMLDocumentHandler 2.0.0b4
0388: public void startDocument(XMLLocator locator, String encoding,
0389: Augmentations a) {
0390:
0391: trace("startDocument()"); // NOI18N
0392:
0393: this .locator = locator;
0394: try {
0395: returnDocument = document = new TreeDocument(null,
0396: null, null);
0397: pushParentNode((TreeDocument) document);
0398: } catch (TreeException exc) {
0399: throw new XNIException(exc);
0400: }
0401: } // startDocument()
0402:
0403: /**
0404: * Notifies of the presence of an XMLDecl line in the document. If
0405: * present, this method will be called immediately following the
0406: * startDocument call.
0407: *
0408: * @param version The XML version.
0409: * @param encoding The IANA encoding name of the document, or null if
0410: * not specified.
0411: * @param standalone The standalone value, or null if not specified.
0412: *
0413: * @throws SAXException Thrown by handler to signal an error.
0414: */
0415: public void xmlDecl(String version, String encoding,
0416: String standalone, Augmentations a) {
0417:
0418: trace("xmlDecl()"); // NOI18N
0419:
0420: try {
0421: ((TreeDocument) document).setHeader(version, encoding,
0422: standalone);
0423: } catch (TreeException exc) {
0424: throw new XNIException(exc);
0425: }
0426: } // xmlDecl(String,String,String)
0427:
0428: // XMLDTDHandler 2.4.0 and XMLDocumentHandler > 2.0.0b4
0429: public void textDecl(String version, String encoding,
0430: Augmentations a) {
0431:
0432: trace("textDecl()"); // NOI18N
0433:
0434: // if we are DTD parser scanning base DTD document entity
0435: if (isXMLDocument == false && inDTD && inEntity() == false) {
0436: try {
0437: ((TreeDTD) document).setHeader(version, encoding);
0438: } catch (TreeException ex) {
0439: throw new XNIException(ex);
0440: }
0441: }
0442: }
0443:
0444: // XMLDTDHAndler 2.0.0b4
0445: public void textDecl(String version, String encoding) {
0446: textDecl(version, encoding, null);
0447: }
0448:
0449: /**
0450: * Notifies of the presence of the DOCTYPE line in the document.
0451: */
0452: public void doctypeDecl(String rootElement, String publicId,
0453: String systemId, Augmentations a) {
0454:
0455: trace("doctypeDecl(" + rootElement + "," + publicId + ")"); // NOI18N
0456:
0457: try {
0458: TreeDocumentType _doctype = new TreeDocumentType(
0459: rootElement, publicId, systemId);
0460: setBeginPosition(_doctype);
0461: ((TreeDocument) document).setDocumentType(_doctype);
0462:
0463: doctype = _doctype;
0464: } catch (TreeException exc) {
0465: throw new XNIException(exc);
0466: }
0467: } // doctypeDecl(String,String,String)
0468:
0469: /**
0470: * The start of an element.
0471: */
0472: public void startElement(QName element,
0473: XMLAttributes attributes, Augmentations a) {
0474:
0475: trace("startElement(" + element + ")"); // NOI18N
0476:
0477: try {
0478: tempNode = new TreeElement(element.rawname);
0479: startElementImpl((TreeElement) tempNode, attributes);
0480:
0481: pushParentNode((TreeElement) tempNode);
0482: elementStack.push(tempNode);
0483:
0484: } catch (TreeException exc) {
0485: throw new XNIException(exc);
0486: }
0487: } // startElement(QName,XMLAttributes)
0488:
0489: /**
0490: * This callback represents <.....<b>/</b>>.
0491: */
0492: public void emptyElement(QName qName, XMLAttributes attributes,
0493: Augmentations a) {
0494:
0495: trace("emptyElement(" + qName + ")"); // NOI18N
0496:
0497: try {
0498: tempNode = new TreeElement(qName.rawname, true);
0499: startElementImpl((TreeElement) tempNode, attributes);
0500: } catch (TreeException exc) {
0501: throw new XNIException(exc);
0502: }
0503: }
0504:
0505: /**
0506: * Insert element and its attributes at hiearchy
0507: */
0508: private void startElementImpl(TreeElement elem,
0509: XMLAttributes attributes) throws TreeException {
0510:
0511: setBeginPosition(elem);
0512:
0513: //??? is it really neccessary
0514: if (currentParentNode() instanceof TreeDocument) {
0515: ((TreeDocument) currentParentNode())
0516: .setDocumentElement(elem);
0517: } else {
0518: appendChild(elem);
0519: }
0520:
0521: // handle attributes
0522:
0523: int attrCount = attributes.getLength();
0524: for (int i = 0; i < attrCount; i++) {
0525: boolean specified = attributes.isSpecified(i);
0526:
0527: if (specified == true) { // TEMPORARY -- not specified nodes will not be added into element
0528:
0529: attributes.getName(i, tmpQName); //fill tmpQName
0530: String val = attributes.getNonNormalizedValue(i); //???getNonNormalizedValue
0531:
0532: TreeAttribute attr; // to be filled
0533:
0534: if (val.indexOf('&') < 0) {
0535:
0536: attr = new TreeAttribute(tmpQName.rawname, val,
0537: specified);
0538:
0539: } else {
0540:
0541: attr = new TreeAttribute(tmpQName.rawname, "",
0542: specified); // NOI18N
0543: List list = attr.getValueList();
0544: list.clear();
0545:
0546: // build attribute value, split content as refs and text
0547:
0548: int lastOffset = 0; // offset
0549: for (int offset = val.indexOf('&'); offset >= 0; offset = val
0550: .indexOf('&', offset + 1)) {
0551:
0552: int endOffset = val.indexOf(';', offset);
0553: String name = val.substring(offset + 1,
0554: endOffset);
0555:
0556: if (offset > lastOffset) {
0557: // insert text
0558: TreeText text = new TreeText(val
0559: .substring(lastOffset, offset));
0560: list.add(text);
0561: }
0562:
0563: if (name.startsWith("#")) { // NOI18N
0564: TreeCharacterReference chref = new TreeCharacterReference(
0565: name);
0566: list.add(chref);
0567: } else {
0568: TreeGeneralEntityReference gref = new TreeGeneralEntityReference(
0569: name);
0570: list.add(gref);
0571: }
0572:
0573: lastOffset = endOffset + 1;
0574: }
0575:
0576: if (val.length() > lastOffset) {
0577: String lastText = val.substring(lastOffset);
0578: list.add(new TreeText(lastText));
0579: }
0580: }
0581:
0582: if (!!!specified) {
0583: setReadOnly(attr);
0584: }
0585: elem.addAttribute(attr);
0586:
0587: } // if ( specified == true )
0588: }
0589:
0590: // recall remenbered internal DTD //!!!
0591:
0592: if (rememberingReader == null) {
0593: return;
0594: }
0595: StringBuffer mem = rememberingReader.stopRemembering();
0596: if (mem == null)
0597: return;
0598:
0599: String idtd = mem.toString();
0600: int start = -1, end = -1; // results
0601: int now, last = -1; // tmps
0602: char delimiter;
0603:
0604: if (Util.THIS.isLoggable()) /* then */
0605: Util.THIS
0606: .debug("TreeStreamBuilderXercesImpl: going to inspect:\n"
0607: + idtd);
0608:
0609: // find out DOCTYPE declaration
0610: // #23197 eliminate doctypes in comment (simple aproximation)
0611:
0612: final String DOCTYPE = "<!DOCTYPE"; // NOI18N
0613: int pos = -1;
0614: DOCTYPE_LOOP: while (true) {
0615: pos = idtd.indexOf(DOCTYPE, ++pos);
0616: if (pos == -1) {
0617: Util.THIS.debug("XNIBuilder: no DOCTYPE detected."); // NOI18N
0618: return;
0619: } else {
0620: int comment = -1;
0621: while (true) {
0622: comment = idtd.indexOf("<!--", ++comment); // NOI18N
0623: if (comment != -1 && comment < pos) {
0624: if (idtd.indexOf("-->", comment) > pos) { // NOI18N
0625: // it is commented out, try another
0626: break;
0627: } else {
0628: // commentd ends before, but it does not proof anything
0629: continue;
0630: }
0631: } else {
0632: break DOCTYPE_LOOP;
0633: }
0634: }
0635: }
0636: }
0637:
0638: if (Util.THIS.isLoggable()) /* then */
0639: Util.THIS.debug("\nlast index = " + pos);
0640:
0641: // skip root element name
0642:
0643: pos += DOCTYPE.length();
0644: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0645: ;
0646: for (; StringUtil.isWS(idtd.charAt(pos)) == false; pos++)
0647: ;
0648: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0649: ;
0650:
0651: if (Util.THIS.isLoggable()) /* then */
0652: Util.THIS.debug("\nafter process index = " + pos);
0653:
0654: // SYSTEM or PUBLIC or [
0655:
0656: if (Util.THIS.isLoggable()) /* then */
0657: Util.THIS.debug("\nTesting DOCTYPE kind-----\n"
0658: + idtd.substring(pos));
0659:
0660: if (idtd.charAt(pos) == '[') { // just internal dtd
0661: start = ++pos;
0662: } else if (idtd.charAt(pos) == 'S') { //SYSTEM "" [
0663: for (; StringUtil.isWS(idtd.charAt(pos)) == false; pos++)
0664: ;
0665: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0666: ;
0667: delimiter = idtd.charAt(pos++);
0668: for (; idtd.charAt(pos) != delimiter; pos++)
0669: ;
0670: pos++;
0671: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0672: ;
0673: if (idtd.charAt(pos) == '[') {
0674: start = ++pos;
0675: }
0676: } else if (idtd.charAt(pos) == 'P') { // PUBLIC "" "" [
0677: for (; StringUtil.isWS(idtd.charAt(pos)) == false; pos++)
0678: ;
0679: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0680: ;
0681: delimiter = idtd.charAt(pos++);
0682: for (; idtd.charAt(pos) != delimiter; pos++)
0683: ;
0684: pos++;
0685: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0686: ;
0687: delimiter = idtd.charAt(pos++);
0688: for (; idtd.charAt(pos) != delimiter; pos++)
0689: ;
0690: pos++;
0691: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0692: ;
0693: if (idtd.charAt(pos) == '[') {
0694: start = ++pos;
0695: }
0696: }
0697:
0698: if (start == -1) {
0699: if (Util.THIS.isLoggable()) /* then */
0700: Util.THIS
0701: .debug("TreeStreamBuilderXercesImpl: it does not have internal DTD.");
0702:
0703: return;
0704: } else {
0705: if (Util.THIS.isLoggable()) /* then */
0706: Util.THIS.debug("\n---Analyzing internal DTD:\n"
0707: + idtd.substring(start));
0708: }
0709:
0710: // search for internal DTD end
0711:
0712: for (last = pos - 1; idtd.startsWith("]>", pos) == false
0713: && last < pos;) {
0714:
0715: last = pos;
0716:
0717: // skip comments and WS
0718: for (; StringUtil.isWS(idtd.charAt(pos)); pos++)
0719: ;
0720:
0721: now = StringUtil
0722: .skipDelimited(idtd, pos, "<!--", "-->");
0723: if (now != -1) {
0724: pos = now;
0725: continue;
0726: }
0727:
0728: // skip PIs
0729: now = StringUtil.skipDelimited(idtd, pos, "<?", "?>");
0730: if (now != -1) {
0731: pos = now;
0732: continue;
0733: }
0734:
0735: // skip decls
0736: now = StringUtil.skipDelimited(idtd, pos, '<', '>',
0737: "\"'");
0738: if (now != -1) {
0739: pos = now;
0740: continue;
0741: }
0742:
0743: // skip references
0744: now = StringUtil.skipDelimited(idtd, pos, '%', ';', "");
0745: if (now != -1) {
0746: pos = now;
0747: continue;
0748: }
0749:
0750: }
0751:
0752: if (last == pos) {
0753: if (Util.THIS.isLoggable()) /* then */
0754: Util.THIS
0755: .debug("TreeStreamBuilderXercesImpl: end not reached");
0756:
0757: return;
0758: }
0759:
0760: String internalDTDText = idtd.substring(start, pos);
0761:
0762: if (Util.THIS.isLoggable()) /* then */
0763: Util.THIS.debug("Internal DTD:" + internalDTDText
0764: + "\n--");
0765:
0766: // use introspectio to set it
0767:
0768: try {
0769: if (doctype == null)
0770: return;
0771: Class klass = doctype.getClass();
0772: Field field = klass.getDeclaredField("internalDTDText");
0773: field.setAccessible(true);
0774: field.set(doctype, internalDTDText);
0775: } catch (RuntimeException ex) {
0776: throw ex;
0777: } catch (Exception ex) {
0778: // ignore introspection exceptions
0779: if (Util.THIS.isLoggable()) /* then */
0780: Util.THIS
0781: .debug(
0782: "TreeStreamBuilderXercesImpl.settingInternaDTDText",
0783: ex);
0784: }
0785:
0786: }
0787:
0788: /**
0789: * Character content.
0790: */
0791: public void characters(XMLString text, Augmentations a) {
0792:
0793: try {
0794: if (inCharacterRef == true)
0795: return; // ignore resolved
0796:
0797: if (inDTD) {
0798: if (currentParentNode() instanceof TreeConditionalSection) {
0799: if (Util.THIS.isLoggable()) /* then */
0800: Util.THIS
0801: .debug("\n*** TreeStreamBuilderXercesImpl::characters: XMLString = '"
0802: + text + "'"); // NOI18N
0803:
0804: ((TreeConditionalSection) currentParentNode())
0805: .setIgnoredContent(text.toString());
0806: }
0807: } else if (inCDATASection) {
0808: cdataSectionBuffer.append(text.toString());
0809: } else {
0810: tempNode = new TreeText(text.toString());
0811: setBeginPosition(tempNode);
0812: appendChild((TreeText) tempNode);
0813: }
0814: } catch (TreeException exc) {
0815: throw new XNIException(exc);
0816: }
0817: } // characters(XMLString)
0818:
0819: // XMLDTDHandler 2.4.0
0820: public void ignoredCharacters(XMLString text, Augmentations a) {
0821: characters(text, null);
0822: }
0823:
0824: // XMLDTDHandler 2.0.0b4
0825: public void characters(XMLString text) {
0826: characters(text, null);
0827: }
0828:
0829: /**
0830: * Ignorable whitespace.
0831: */
0832: public void ignorableWhitespace(XMLString text, Augmentations a) {
0833: try {
0834: tempNode = new TreeText(text.toString()); //???
0835: setBeginPosition(tempNode);
0836: appendChild((TreeText) tempNode);
0837: } catch (TreeException exc) {
0838: throw new XNIException(exc);
0839: }
0840: } // ignorableWhitespace(XMLString)
0841:
0842: /**
0843: * The end of an element.
0844: */
0845: public void endElement(QName element, Augmentations a) {
0846: trace("endElement(" + element + ")"); // NOI18N
0847:
0848: try {
0849: TreeElement el = (TreeElement) elementStack.pop();
0850: el.normalize(); //??? parser return multiline text as multiple characters()
0851: popParentNode();
0852: } catch (TreeException exc) {
0853: throw new XNIException(exc);
0854: }
0855: } // endElement(QName)
0856:
0857: /**
0858: * The start of a CDATA section. Buffer its content.
0859: */
0860: public void startCDATA(Augmentations a) {
0861: inCDATASection = true;
0862: cdataSectionBuffer.delete(0, cdataSectionBuffer.length());
0863: //!!! save position
0864: } // startCDATA()
0865:
0866: /**
0867: * The end of a CDATA section.
0868: */
0869: public void endCDATA(Augmentations a) {
0870:
0871: inCDATASection = false;
0872:
0873: try {
0874: tempNode = new TreeCDATASection(cdataSectionBuffer
0875: .toString());
0876: setBeginPosition(tempNode); //!!! error
0877: appendChild((TreeCDATASection) tempNode);
0878: } catch (TreeException exc) {
0879: throw new XNIException(exc);
0880: }
0881: } // endCDATA()
0882:
0883: /**
0884: * The end of the document.
0885: */
0886: public void endDocument(Augmentations a) {
0887: trace("endDocument()"); // NOI18N
0888:
0889: if (parentObjectListStack.isEmpty() == false) {
0890: if (Util.THIS.isLoggable()) /* then */
0891: Util.THIS.debug("Inconsistency at parentStack: "
0892: + parentObjectListStack); // NOI18N
0893: } else if (elementStack.isEmpty() == false) {
0894: if (Util.THIS.isLoggable()) /* then */
0895: Util.THIS.debug("Inconsistency at elementStack: "
0896: + parentObjectListStack); // NOI18N
0897: } else {
0898: isCorrect = true;
0899: }
0900: } // endDocument()
0901:
0902: //
0903: // XMLDocumentHandler and XMLDTDHandler methods
0904: //
0905:
0906: public void endPrefixMapping(String prefix, Augmentations a) {
0907: // not interested
0908: }
0909:
0910: public void startPrefixMapping(String prefix, String uri,
0911: Augmentations a) {
0912: // not interested
0913: }
0914:
0915: // XMLDTDHandler 2.4.0
0916: public void startExternalSubset(XMLResourceIdentifier entity,
0917: Augmentations a) {
0918: startEntity("[dtd]", entity.getPublicId(), entity
0919: .getLiteralSystemId(), entity.getBaseSystemId(),
0920: null, a);
0921: }
0922:
0923: public void startGeneralEntity(String name,
0924: XMLResourceIdentifier entity, String encoding,
0925: Augmentations a) {
0926: startEntity(name, entity.getPublicId(), entity
0927: .getLiteralSystemId(), entity.getBaseSystemId(),
0928: encoding, a);
0929: }
0930:
0931: /**
0932: * This method notifies of the start of an entity. The document entity
0933: * has the pseudo-name of "[xml]"; The DTD has the pseudo-name of "[dtd];
0934: * parameter entity names start with '%'; and general entity names are
0935: * just the entity name.
0936: *
0937: * @param encoding special value of "IGNORE" markg parameter
0938: * entities in DTD markup (these are ignored)
0939: */
0940: private void startEntity(String name, String publicId,
0941: String systemId, String baseSystemId, String encoding,
0942: Augmentations a) {
0943:
0944: trace("startEntity(" + name + ")"); // NOI18N
0945:
0946: try {
0947:
0948: // do not theat these as external entities
0949: // DTD is wrapped intentionally
0950:
0951: if (XML_ENTITY.equals(name))
0952: return;
0953: if (isXMLDocument == false && DTD_ENTITY.equals(name))
0954: return;
0955:
0956: if (DTD_ENTITY.equals(name) && isXMLDocument) {
0957:
0958: hasExternalDTD = true;
0959:
0960: // we are entering external DTD attach all to DOCTYPE ObjectList
0961: // There is performance optimalization: External DTD model
0962: // can be shared among several instances referring it.
0963: // It's currently managed by the TreeDocumentType class
0964: TreeObjectList external = doctype.getExternalDTD();
0965: if (external == null) {
0966: TreeDTDFragment entity = new TreeDTDFragment();
0967: TreeObjectList holder = entity.getChildNodes();
0968: pushParentObjectList(holder);
0969: doctype.setExternalDTD(entity);
0970: } else {
0971: // It was already parsed, ignore its content
0972: pushParentObjectList(null);
0973: }
0974:
0975: } else if (name.startsWith("#")) { // NOI18N
0976:
0977: tempNode = new TreeCharacterReference(name);
0978: appendChild(tempNode);
0979: setBeginPosition(tempNode);
0980: inCharacterRef = true;
0981:
0982: } else if ("lt".equals(name) || "gt".equals(name)
0983: || "amp".equals(name) // NOI18N
0984: || "apos".equals(name) || "quot".equals(name)) { // NOI18N
0985:
0986: tempNode = new TreeGeneralEntityReference(name);
0987: appendChild(tempNode);
0988: setBeginPosition(tempNode);
0989: inCharacterRef = true;
0990:
0991: } else if (name.startsWith("%")) { // NOI18N
0992:
0993: if ("IGNORE".equals(encoding)) { // NOI18N
0994: // skip entities in markup, place the into unattached list
0995: name = name.substring(1);
0996: pushParentNode(new TreeParameterEntityReference(
0997: name));
0998:
0999: } else {
1000: name = name.substring(1);
1001: tempNode = new TreeParameterEntityReference(
1002: name); //??? external entities
1003: appendChild((TreeParameterEntityReference) tempNode);
1004: setBeginPosition(tempNode);
1005: pushParentNode((TreeEntityReference) tempNode);
1006: }
1007:
1008: } else {
1009:
1010: tempNode = new TreeGeneralEntityReference(name); //??? external entities
1011: appendChild((TreeGeneralEntityReference) tempNode);
1012: setBeginPosition(tempNode);
1013: pushParentNode((TreeEntityReference) tempNode);
1014:
1015: }
1016:
1017: enterEntity();
1018:
1019: } catch (TreeException exc) {
1020: throw new XNIException(exc);
1021: }
1022: } // startEntity(String,String,String,String)
1023:
1024: // XMLDTDHandler 2.0.0b4
1025: public void startEntity(String name, String publicId,
1026: String systemId, String baseSystemId, String encoding) {
1027: startEntity(name, publicId, systemId, baseSystemId,
1028: encoding, null);
1029: }
1030:
1031: // XMLDTDHanlder 2.4.0
1032: public void startParameterEntity(String name,
1033: XMLResourceIdentifier entity, String encoding,
1034: Augmentations a) {
1035: String pname = name;
1036: if (false == name.startsWith("%")) {
1037: pname = "%" + name;
1038: }
1039: startEntity(pname, entity.getPublicId(), entity
1040: .getLiteralSystemId(), entity.getBaseSystemId(),
1041: encoding, a);
1042: }
1043:
1044: /**
1045: * A comment.
1046: */
1047: // XMLDTDHandler 2.4.0 and XMLDocumentHandler
1048: public void comment(XMLString text, Augmentations a) {
1049:
1050: trace("comment()"); // NOI18N
1051:
1052: try {
1053: tempNode = new TreeComment(text.toString());
1054: setBeginPosition(tempNode);
1055: appendChild((TreeComment) tempNode);
1056: } catch (TreeException exc) {
1057: throw new XNIException(exc);
1058: }
1059: } // comment(XMLString)
1060:
1061: // XMLDTDHandler 2.0.0b4
1062: public void comment(XMLString text) {
1063: comment(text, null);
1064: }
1065:
1066: /**
1067: * A processing instruction. Processing instructions consist of a
1068: * target name and, optionally, text data. The data is only meaningful
1069: * to the application.
1070: */
1071: // XMLDTDHandler 2.4.0 and XMLDocumentHandler > 2.0.0b4
1072: public void processingInstruction(String target,
1073: XMLString data, Augmentations a) {
1074:
1075: trace("processingInstruction(" + target + ")"); // NOI18N
1076:
1077: try {
1078: tempNode = new TreeProcessingInstruction(target, data
1079: .toString());
1080: setBeginPosition(tempNode);
1081: appendChild((TreeProcessingInstruction) tempNode);
1082: } catch (TreeException exc) {
1083: throw new XNIException(exc);
1084: }
1085: } // processingInstruction(String,XMLString)
1086:
1087: // XMLDTDHandler 2.0.0b4
1088: public void processingInstruction(String target, XMLString data) {
1089: processingInstruction(target, data, null);
1090: }
1091:
1092: // XMLDTDHandler 2.4.0
1093: public void endExternalSubset(Augmentations a) {
1094: endEntity("[dtd]", a);
1095: }
1096:
1097: // XMLDTDHandler 2.4.0
1098: public void endParameterEntity(String name, Augmentations a) {
1099: String pname = name;
1100: if (false == name.startsWith("%")) {
1101: pname = "%" + name;
1102: }
1103: endEntity(pname, a);
1104: }
1105:
1106: public void endGeneralEntity(String name, Augmentations a) {
1107: endEntity(name, a);
1108: }
1109:
1110: /**
1111: * This method notifies the end of an entity. The document entity has
1112: * the pseudo-name of "[xml]"; the DTD has the pseudo-name of "[dtd];
1113: * parameter entity names start with '%'; and general entity names are
1114: * just the entity name.
1115: */
1116: private void endEntity(String name, Augmentations a) {
1117: trace("endEntity(" + name + ")"); // NOI18N
1118:
1119: // skip for root entities of XML documents and
1120: // standalone DTDs parsed by DTD parser
1121:
1122: if (XML_ENTITY.equals(name))
1123: return;
1124: if (isXMLDocument == false && DTD_ENTITY.equals(name))
1125: return;
1126:
1127: exitEntity();
1128:
1129: if (inCharacterRef == true) {
1130: inCharacterRef = false;
1131: return;
1132: }
1133:
1134: if (isXMLDocument && DTD_ENTITY.equals(name)) {
1135: popParentObjectList(); // DOCTYPE ObjectList
1136: } else {
1137: popParentNode();
1138: }
1139:
1140: } // endEntity(String)
1141:
1142: //??? DTDHandler
1143: public void endEntity(String name) {
1144: endEntity(name, null);
1145: }
1146:
1147: // XMLDTDHandler methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1148:
1149: // XMLDTDHandler 2.4.0
1150: public XMLDTDSource getDTDSource() {
1151: return xmldtdSource;
1152: }
1153:
1154: // XMLDTDHandler 2.4.0
1155: public void setDTDSource(XMLDTDSource src) {
1156: xmldtdSource = src;
1157: }
1158:
1159: // XMLDTDHandler 2.0.0b4
1160: public void startDTD(XMLLocator locator, Augmentations a) {
1161: startDTD(locator);
1162: }
1163:
1164: /**
1165: * The start of the DTD (external part of it is reported by startEntity).
1166: */
1167: // XMLDTDHandler 2.0.0b4
1168: public void startDTD(XMLLocator locator) {
1169: trace("startDTD()"); // NOI18N
1170:
1171: try {
1172: inDTD = true;
1173:
1174: if (isXMLDocument) {
1175:
1176: pushParentNode(doctype);
1177:
1178: } else {
1179:
1180: // replace returnDocument
1181: returnDocument = document = new TreeDTD(null, null);
1182: pushParentNode((TreeDTD) document);
1183: }
1184: } catch (TreeException exc) {
1185: throw new XNIException(exc);
1186: }
1187: } // startDTD()
1188:
1189: // XMLDTDHandler 2.4.0
1190: public void elementDecl(String name, String contentModel,
1191: Augmentations a) {
1192: elementDecl(name, contentModel);
1193: }
1194:
1195: /**
1196: * An element declaration.
1197: */
1198: // XMLDTDHandler 2.0.0b4
1199: public void elementDecl(String name, String cM) {
1200: trace("elementDecl(" + name + ")"); // NOI18N
1201: if (ASSERT)
1202: doAssert(inDTD);
1203:
1204: try {
1205: appendChild(new TreeElementDecl(name, this .contentModel));
1206: this .contentModel = null;
1207: } catch (TreeException exc) {
1208: throw new XNIException(exc);
1209: }
1210:
1211: } // elementDecl(String,String)
1212:
1213: // XMLDTDHandler 2.4.0
1214: public void startAttlist(String elementName, Augmentations a) {
1215: startAttlist(elementName);
1216: }
1217:
1218: /**
1219: * The start of an attribute list.
1220: */
1221: // XMLDTDHandler 2.0.0b4
1222: public void startAttlist(String elementName) {
1223:
1224: trace("startAttlist(" + elementName + ")"); // NOI18N
1225:
1226: try {
1227: tempNode = new TreeAttlistDecl(elementName);
1228: attlistDecl = (TreeAttlistDecl) tempNode;
1229: appendChild(attlistDecl);
1230: } catch (TreeException exc) {
1231: throw new XNIException(exc);
1232: }
1233: } // startAttlist(String)
1234:
1235: // XMLDTDHandler 2.4.0
1236: public void attributeDecl(String elementName,
1237: String attributeName, String type,
1238: String[] enumeration, String defaultType,
1239: XMLString defaultValue,
1240: XMLString nonNormalizedDefaultValue, Augmentations a) {
1241: attributeDecl(elementName, attributeName, type,
1242: enumeration, defaultType, defaultValue);
1243: }
1244:
1245: /**
1246: * An attribute declaration.
1247: */
1248: // XMLDTDHandler 2.0.0b4
1249: public void attributeDecl(String elementName,
1250: String attributeName, String type,
1251: String[] enumeration, String defaultType,
1252: XMLString defaultValue) {
1253:
1254: trace("attributeDecl(" + attributeName + ")"); // NOI18N
1255:
1256: try {
1257: TreeAttlistDecl list;
1258:
1259: if (attlistDecl != null) {
1260: list = attlistDecl;
1261: } else {
1262: list = new TreeAttlistDecl(elementName);
1263: }
1264: if (type.equals("ENUMERATION")) { // NOI18N
1265: type = null;
1266: }
1267:
1268: short shortDefaultType = TreeAttlistDeclAttributeDef
1269: .findDefaultType(defaultType);
1270: String newDefaultValue = null;
1271: if ((shortDefaultType == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_NULL)
1272: || (shortDefaultType == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_FIXED)) {
1273: newDefaultValue = defaultValue.toString();
1274: }
1275: TreeAttlistDeclAttributeDef decl = new TreeAttlistDeclAttributeDef(
1276: attributeName, TreeAttlistDeclAttributeDef
1277: .findType(type), enumeration,
1278: shortDefaultType, newDefaultValue);
1279:
1280: list.setAttributeDef(decl);
1281: } catch (TreeException exc) {
1282: //Util.dumpContext("TreeAttlistDecl.setReadOnly(true)"); // NOI18N
1283: throw new XNIException(exc);
1284: }
1285: } // attributeDecl(String,String,String,String[],String,XMLString)
1286:
1287: // XMLDTDHandler 2.4.0
1288: public void endAttlist(Augmentations a) {
1289: endAttlist();
1290: }
1291:
1292: /**
1293: * The end of an attribute list.
1294: */
1295: // XMLDTDHandler 2.0.0b4
1296: public void endAttlist() {
1297:
1298: trace("endAttlist()"); // NOI18N
1299:
1300: attlistDecl = null;
1301: } // endAttlist()
1302:
1303: // XMLDTDHandler 2.4.0
1304: public void internalEntityDecl(String name, XMLString text,
1305: XMLString nonNormalizedText, Augmentations a) {
1306: internalEntityDecl(name, text, nonNormalizedText);
1307: }
1308:
1309: /**
1310: * An internal entity declaration.
1311: *
1312: * @param name The name of the entity. Parameter entity names start with
1313: * '%', whereas the name of a general entity is just the
1314: * entity name.
1315: */
1316: // XMLDTDHandler 2.0.0b4
1317: public void internalEntityDecl(String name, XMLString text,
1318: XMLString nonNormalizedText) {
1319:
1320: trace("internalEntityDecl(" + name + ")"); // NOI18N
1321:
1322: try {
1323: boolean par = name.startsWith("%"); // NOI18N
1324: if (par) {
1325: name = name.substring(1);
1326: }
1327: appendChild(new TreeEntityDecl(par, name, text
1328: .toString()));
1329: } catch (TreeException exc) {
1330: throw new XNIException(exc);
1331: }
1332: } // internalEntityDecl(String,XMLString)
1333:
1334: // XMLDTDHandler 2.4.0
1335: public void externalEntityDecl(String name, String publicId,
1336: String systemId, String baseSystemId, Augmentations a) {
1337: externalEntityDecl(name, publicId, systemId, baseSystemId);
1338: }
1339:
1340: /**
1341: * An external entity declaration.
1342: *
1343: * @param name The name of the entity. Parameter entity names start
1344: * with '%', whereas the name of a general entity is just
1345: * the entity name.
1346: */
1347: // XMLDTDHandler 2.0.0b4
1348: public void externalEntityDecl(String name, String publicId,
1349: String systemId, String baseSystemId) {
1350:
1351: trace("externalEntityDecl(" + name + ")"); // NOI18N
1352:
1353: try {
1354: boolean par = name.startsWith("%"); // NOI18N
1355: if (par) {
1356: name = name.substring(1);
1357: }
1358:
1359: appendChild(new TreeEntityDecl(par, name, publicId,
1360: systemId));
1361: } catch (TreeException exc) {
1362: throw new XNIException(exc);
1363: }
1364: } // externalEntityDecl(String,String,String)
1365:
1366: // XMLDTDHAnlder 2.4.0
1367: public void unparsedEntityDecl(String name, String publicId,
1368: String systemId, String notation, Augmentations a) {
1369: unparsedEntityDecl(name, publicId, systemId, notation);
1370: }
1371:
1372: /**
1373: * An unparsed entity declaration.
1374: */
1375: // XMLDTDHAnlder 2.0.0b4
1376: public void unparsedEntityDecl(String name, String publicId,
1377: String systemId, String notation) {
1378:
1379: trace("unparsedEntityDecl(" + name + ")"); // NOI18N
1380:
1381: try {
1382: appendChild(new TreeEntityDecl(name, publicId,
1383: systemId, notation));
1384: } catch (TreeException exc) {
1385: throw new XNIException(exc);
1386: }
1387: } // unparsedEntityDecl(String,String,String,String)
1388:
1389: // XMLDTDHandler 2.4.0
1390: public void notationDecl(String name, String publicId,
1391: String systemId, Augmentations a) {
1392: notationDecl(name, publicId, systemId);
1393: }
1394:
1395: /**
1396: * A notation declaration
1397: */
1398: // XMLDTDHandler 2.0.0b4
1399: public void notationDecl(String name, String publicId,
1400: String systemId) {
1401:
1402: trace("notationDecl(" + name + ")"); // NOI18N
1403:
1404: try {
1405: appendChild(new TreeNotationDecl(name, publicId,
1406: systemId));
1407: } catch (TreeException exc) {
1408: throw new XNIException(exc);
1409: }
1410: } // notationDecl(String,String,String)
1411:
1412: // XMLDTDHandler 2.4.0
1413: public void startConditional(short type, Augmentations a) {
1414: startConditional(type);
1415: }
1416:
1417: /**
1418: * The start of a conditional section.
1419: *
1420: * @param type The type of the conditional section. This value will
1421: * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
1422: */
1423: // XMLDTDHandler 2.0.0b4
1424: public void startConditional(short type) {
1425: trace("startConditional(" + type + ")"); // NOI18N
1426: if (ASSERT)
1427: doAssert(inDTD);
1428:
1429: if (type == CONDITIONAL_INCLUDE) {
1430: tempNode = new TreeConditionalSection(true);
1431: } else {
1432: tempNode = new TreeConditionalSection(false);
1433: }
1434:
1435: appendChild((TreeConditionalSection) tempNode);
1436: setBeginPosition(tempNode);
1437: pushParentNode((TreeConditionalSection) tempNode);
1438:
1439: } // startConditional(short)
1440:
1441: // XMLDTDHandler 2.4.0
1442: public void endConditional(Augmentations a) {
1443: endConditional();
1444: }
1445:
1446: /**
1447: * The end of a conditional section.
1448: */
1449: // XMLDTDHandler 2.0.0b4
1450: public void endConditional() {
1451: trace("endConditional()"); // NOI18N
1452:
1453: popParentNode();
1454: } // endConditional()
1455:
1456: // XMLDTDHandler 2.4.0
1457: public void endDTD(Augmentations a) {
1458: endDTD();
1459: }
1460:
1461: /**
1462: * The end of the DTD.
1463: *
1464: * @throws SAXException Thrown by handler to signal an error.
1465: */
1466: // XMLDTDHandler 2.0.0b4
1467: public void endDTD() {
1468: trace("endDTD()"); // NOI18N
1469:
1470: if (isXMLDocument) {
1471:
1472: popParentNode();
1473:
1474: } else {
1475:
1476: popParentNode();
1477:
1478: //??? Xerces miss '<' at the end of entity
1479: // so such documents are reported as correct
1480:
1481: isCorrect = errors == 0;
1482: throw new DTDStopException();
1483:
1484: }
1485:
1486: inDTD = false;
1487: } // endDTD()
1488:
1489: // Content Model parser ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1490:
1491: private TreeElementDecl.ContentType lastType; // occurence operators are applied on this
1492: private TreeElementDecl.ContentType contentModel; // OUTPUT result field
1493: private Stack contentModelMembersStack; // stack of parent group members
1494:
1495: public XMLDTDContentModelSource getDTDContentModelSource() {
1496: return xmldtdContentModelSource;
1497: }
1498:
1499: public void setDTDContentModelSource(
1500: XMLDTDContentModelSource src) {
1501: xmldtdContentModelSource = src;
1502: }
1503:
1504: public void startContentModel(String elementName,
1505: Augmentations a) {
1506:
1507: if (Util.THIS.isLoggable()) /* then */
1508: Util.THIS.debug("startContentModel(" + elementName
1509: + ")"); // NOI18N
1510:
1511: lastType = null;
1512: contentModelMembersStack = new Stack();
1513:
1514: }
1515:
1516: public void any(Augmentations a) {
1517: contentModel = new ANYType();
1518: }
1519:
1520: public void empty(Augmentations a) {
1521: contentModel = new EMPTYType();
1522: }
1523:
1524: public void pcdata(Augmentations a) {
1525: setMembersType(new MixedType());
1526: }
1527:
1528: // it is not called for mixed type
1529: public void startGroup(Augmentations a) {
1530: if (Util.THIS.isLoggable()) /* then */
1531: Util.THIS.debug("startGroup()"); // NOI18N
1532:
1533: startMembers();
1534: }
1535:
1536: public void element(String elementName, Augmentations a) {
1537:
1538: if (Util.THIS.isLoggable()) /* then */
1539: Util.THIS.debug("element(" + elementName + ")"); // NOI18N
1540:
1541: lastType = new NameType(elementName);
1542: addMember(lastType);
1543: }
1544:
1545: // determine type of content model group
1546: public void separator(short separator, Augmentations a) {
1547: if (Util.THIS.isLoggable()) /* then */
1548: Util.THIS.debug("childrenSeparator()"); // NOI18N
1549:
1550: switch (separator) {
1551: case SEPARATOR_SEQUENCE:
1552: setMembersType(new SequenceType());
1553: break;
1554: case SEPARATOR_CHOICE:
1555: setMembersType(new ChoiceType());
1556: break;
1557: default:
1558: doAssert(false);
1559: }
1560: }
1561:
1562: //
1563: // INPUT lastType field
1564: //
1565: public void occurrence(short occurrence, Augmentations a) {
1566: if (Util.THIS.isLoggable()) /* then */
1567: Util.THIS.debug("childrenOccurrence()"); // NOI18N
1568:
1569: switch (occurrence) {
1570: case OCCURS_ZERO_OR_ONE:
1571: lastType.setMultiplicity('?');
1572: break;
1573: case OCCURS_ZERO_OR_MORE:
1574: lastType.setMultiplicity('*');
1575: break;
1576: case OCCURS_ONE_OR_MORE:
1577: lastType.setMultiplicity('+');
1578: break;
1579: default:
1580: doAssert(false);
1581: }
1582:
1583: }
1584:
1585: public void endGroup(Augmentations a) {
1586: if (Util.THIS.isLoggable()) /* then */
1587: Util.THIS.debug("childrenEndGroup()"); // NOI18N
1588:
1589: ChildrenType group = getMembersType();
1590: group.addTypes(endMembers());
1591: lastType = group;
1592: addMember(lastType);
1593: }
1594:
1595: public void endContentModel(Augmentations a) {
1596: if (Util.THIS.isLoggable()) /* then */
1597: Util.THIS.debug("endContentModel()"); // NOI18N
1598:
1599: if (contentModel == null && lastType == null) { // #PCDATA
1600: contentModel = new MixedType();
1601: } else if (contentModel == null) { // we are of CHILDREN_TYPE or mixed type
1602: contentModel = lastType;
1603: if (contentModel instanceof MixedType) {
1604: contentModel.setMultiplicity('*');
1605: }
1606: }
1607: }
1608:
1609: private void startMembers() {
1610: contentModelMembersStack.push(new Members(13));
1611: }
1612:
1613: private void addMember(TreeElementDecl.ContentType child) {
1614:
1615: // we are at top level of content model, lastType becomes it
1616: if (contentModelMembersStack.isEmpty())
1617: return;
1618:
1619: Collection members = (Collection) contentModelMembersStack
1620: .peek();
1621: members.add(child);
1622: }
1623:
1624: private Collection endMembers() {
1625: return (Collection) contentModelMembersStack.pop();
1626: }
1627:
1628: // we can predict member group now, if know balk it
1629: private void setMembersType(ChildrenType group) {
1630:
1631: // we are at top level of content model, lastType becomes it
1632: if (contentModelMembersStack.isEmpty())
1633: return;
1634:
1635: Members members = (Members) contentModelMembersStack.peek();
1636: if (members.group == null)
1637: members.group = group;
1638: }
1639:
1640: private ChildrenType getMembersType() {
1641: Members members = (Members) contentModelMembersStack.peek();
1642: if (members.group == null) {
1643: return new ChoiceType();
1644: } else {
1645: return members.group;
1646: }
1647: }
1648:
1649: //
1650: // Hold additional information about group that holds these members
1651: //
1652: private class Members extends ArrayList {
1653:
1654: private ChildrenType group;
1655:
1656: private static final long serialVersionUID = 4614355994187952965L;
1657:
1658: public Members(int initSize) {
1659: super (initSize);
1660: group = null;
1661: }
1662: }
1663:
1664: // ~~~~~~~~~~~~~~~~~ ERROR HANDLER ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1665:
1666: public void error(org.xml.sax.SAXParseException e) {
1667: trace(e.getMessage());
1668:
1669: errorHandler.message(
1670: TreeStreamBuilderErrorHandler.ERROR_ERROR, e);
1671: }
1672:
1673: public void warning(org.xml.sax.SAXParseException e) {
1674: trace(e.getMessage());
1675:
1676: errorHandler.message(
1677: TreeStreamBuilderErrorHandler.ERROR_WARNING, e);
1678: }
1679:
1680: public void fatalError(org.xml.sax.SAXParseException e) {
1681: trace(e.getMessage());
1682:
1683: errors++;
1684: errorHandler.message(
1685: TreeStreamBuilderErrorHandler.ERROR_FATAL_ERROR, e);
1686: }
1687:
1688: // ~~~~~~~~~~~~~~~~~~ UTILITY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1689:
1690: /**
1691: */
1692: private void setReadOnly(TreeObject treeObject) {
1693: setReadOnly(treeObject, true);
1694: }
1695:
1696: private void setReadOnly(TreeObject treeObject, boolean value) {
1697: try {
1698: Method setReadOnlyMethod = TreeObject.class
1699: .getDeclaredMethod("setReadOnly",
1700: new Class[] { Boolean.TYPE }); // NOI18N
1701: setReadOnlyMethod.setAccessible(true);
1702: setReadOnlyMethod.invoke(treeObject,
1703: new Object[] { value == true ? Boolean.TRUE
1704: : Boolean.FALSE });
1705: } catch (NoSuchMethodException exc) {
1706: } catch (IllegalAccessException exc) {
1707: } catch (InvocationTargetException exc) {
1708: }
1709: }
1710:
1711: /**
1712: * As positons will be supported
1713: */
1714: private void setBeginPosition(TreeNode n) {
1715: //!!!
1716: }
1717:
1718: /**
1719: * @return TreeDocument or null if fatal errors occured
1720: */
1721: private TreeDocumentRoot getDocumentRoot() {
1722: TreeDocumentRoot doc = (TreeDocumentRoot) (errors > 0 ? null
1723: : returnDocument);
1724:
1725: if (Util.THIS.isLoggable()) /* then */
1726: Util.THIS.debug("TreeStreamBuilderXercesImpl returns: "
1727: + doc); // NOI18N
1728:
1729: return doc;
1730: }
1731:
1732: /**
1733: * Shortcut - retrieves child list and pushes it at stack
1734: */
1735: private void pushParentNode(TreeParentNode parent) {
1736: parentNodeStack.push(parent);
1737: pushParentObjectList(parent.getChildNodes());
1738: }
1739:
1740: /**
1741: * Set new parent list pushing original one to node stack
1742: */
1743: private void pushParentObjectList(TreeObjectList parentList) {
1744: parentObjectListStack.push(parentObjectList);
1745:
1746: // inherit null parents (for nested parents)
1747: if (parentObjectList != null
1748: || parentObjectListStack.size() == 1) {
1749: parentObjectList = parentList;
1750: } else {
1751: parentObjectList = null;
1752: }
1753: }
1754:
1755: /**
1756: * Restore current children list poping it from stack.
1757: */
1758: private void popParentObjectList() {
1759: parentObjectList = (TreeObjectList) parentObjectListStack
1760: .pop();
1761: }
1762:
1763: /**
1764: * Resotore parent node and its list from stack
1765: */
1766: private void popParentNode() {
1767: popParentObjectList();
1768: TreeParentNode parentNode = (TreeParentNode) parentNodeStack
1769: .pop();
1770:
1771: // referenced things and DTD things are read only
1772:
1773: if (parentNode instanceof TreeGeneralEntityReference) { // entities in XML doc
1774:
1775: setReadOnly(parentNode.getChildNodes());
1776:
1777: } else if (parentNode instanceof TreeDTD) { // whole DTD
1778:
1779: setReadOnly(parentNode);
1780:
1781: } else if (parentNode instanceof TreeDocumentType) {
1782:
1783: setReadOnly(parentNode.getChildNodes());
1784:
1785: // there can be pure internal DTD
1786: TreeObjectList externalDTD = ((TreeDocumentType) parentNode)
1787: .getExternalDTD();
1788: if (externalDTD != null) {
1789: setReadOnly(externalDTD);
1790: }
1791: }
1792: }
1793:
1794: private TreeParentNode currentParentNode() {
1795: return (TreeParentNode) parentNodeStack.peek();
1796: }
1797:
1798: /**
1799: * Add child to current parent list.
1800: */
1801: private void appendChild(TreeObject child) {
1802: if (parentObjectList != null)
1803: parentObjectList.add(child);
1804: }
1805:
1806: /**
1807: * Enter entity, following events origanes from entity resolution
1808: */
1809: private void enterEntity() {
1810: entityCounter++;
1811: }
1812:
1813: /**
1814: * Exit entity.
1815: */
1816: private void exitEntity() {
1817: entityCounter--;
1818: }
1819:
1820: /**
1821: * Test whether we are in entity, i.e. creating readonly nodes.
1822: */
1823: private boolean inEntity() {
1824: return entityCounter > 0;
1825: }
1826:
1827: private void trace(String msg) {
1828: if (Util.THIS.isLoggable()) {
1829: String location = "";
1830: if (locator != null) {
1831: String entity = locator.getExpandedSystemId();
1832: int index = entity.lastIndexOf('/');
1833: entity = entity.substring(index > 0 ? index : 0);
1834: location = entity + "/" + locator.getLineNumber()
1835: + ":" + locator.getColumnNumber();
1836: }
1837: Util.THIS.debug("X2T " + location + " " + msg); // NOI18N
1838: }
1839: }
1840:
1841: private void doAssert(boolean asrt) {
1842: if (asrt == false) {
1843: throw new IllegalStateException("ASSERT"); // NOI18N
1844: }
1845: }
1846:
1847: }
1848:
1849: }
|