All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enhydra.xml.xmlc.parsers.DocBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: DocBuilder.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.parsers;

import java.util.ArrayList;

import org.enhydra.xml.xmlc.XMLCError;
import org.enhydra.xml.xmlc.XMLCException;
import org.enhydra.xml.xmlc.dom.XMLCDocument;
import org.enhydra.xml.xmlc.dom.XMLCDomFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Node;

/**
 * Class for building a Document DOM.  Used by XMLC XML parsers to build a DOM
 * as well as collect other information about the document.
 * 

* The document builder functions assume they are being called in the order the * document is parsed. They keep a current node where new child nodes are * appended. */ public class DocBuilder { /** * Default XML encoding. */ private static final String DEFAULT_XML_ENCODING = "UTF-8"; /** * Factory for creating the document. */ private XMLCDomFactory fDomFactory; /** * XMLC container for document. */ private XMLCDocument fXmlcDoc; /** * The document. */ private Document fDocument; /** * Information from the DocumentType. */ private String fDocTypeName; // Root element. private String fPublicId; private String fSystemId; /* * Internal subset as a string. */ private String fInternalSubsetStr; /** * The current node that is being constructed. This functions * as a stack during document construction. */ protected Node fCurrentNode; /** * Holds comments and processing instructions before the first element * until the first element is encountered. Comments are strings, * processing instructions are string arrays of length two. */ private ArrayList fPendingPreDocument; /** * Constructor. * * @param domFactory Factory class for Documents. */ public DocBuilder(XMLCDomFactory domFactory) throws XMLCException { fDomFactory = domFactory; fXmlcDoc = new XMLCDocument(domFactory); } /** * Generate an error if the doc type has been created, indicating * a bug in the code using this class. */ private void checkIfAlreadyCreated() { if (fDocument != null) { throw new XMLCError("XMLC bug: attempt to add document type data after DocumentType object has been created"); } } /** * Set the XML version. * * @param xmlVersion XML version string. */ public void setXMLVersion(String xmlVersion) { fXmlcDoc.setXMLVersion(xmlVersion); } /** * Set the encoding for the document. * * @param encoding The encoding for the document. */ public void setEncoding(String encoding) { fXmlcDoc.setEncoding(encoding); } /** * Set the document type name (rootElement). * * @param docTypeName The Document type name (also root node name). */ public void setDocumentTypeName(String docTypeName) { checkIfAlreadyCreated(); fDocTypeName = docTypeName; } /** * Set the publicId. * * @param publicId Document type public id or null if standalone. */ public void setPublicId(String publicId) { checkIfAlreadyCreated(); fPublicId = publicId; } /** * Set the systemId. * * @param systemId Document type system id or null if standalone. */ public void setSystemId(String systemId) { checkIfAlreadyCreated(); fSystemId = systemId; } /** * Add internal subset as a single string. */ public void setInternalSubset(String subsetStr) { checkIfAlreadyCreated(); fInternalSubsetStr = subsetStr; } /** * Flag a element as having #PCDATA as part of its content model. */ public void addPCDataContentElement(String elementName) { checkIfAlreadyCreated(); fXmlcDoc.addPCDataContentElement(elementName); } /** * Define an element id attribute. */ public void addIdAttribute(String elementName, String attributeName) { checkIfAlreadyCreated(); fXmlcDoc.addIdAttribute(elementName, attributeName); } /** * Generate error about a method being called that should be called before * the document is created. */ private void docNotCreatedError() { throw new XMLCError("Bug: parser event on document contents occured before document is created"); } /** * Hold a comment until the start of the document. */ private void holdComment(String data) { if (fPendingPreDocument == null) { fPendingPreDocument = new ArrayList(); } fPendingPreDocument.add(data); } /** * Hold a processing instruction until the start of the document. */ private void holdProcessingInstruction(String target, String data) { if (fPendingPreDocument == null) { fPendingPreDocument = new ArrayList(); } fPendingPreDocument.add(new String[]{target, data}); } /** * Add in comments and processing instructions that occured before the * first element. */ private void addPendingPreDocument() { // Add comments before document element. Node first = fDocument.getFirstChild(); for (int idx = 0; idx < fPendingPreDocument.size(); idx++) { Object entry = fPendingPreDocument.get(idx); if (entry instanceof String) { fDocument.insertBefore(fDocument.createComment((String)entry), first); } else { String[] pi = (String[])entry; fDocument.insertBefore(fDocument.createProcessingInstruction(pi[0], pi[1]), first); } } } /** * Create the Document object when the first element of the document is * found. This is delayed until the the first element, since all * information needed to build the document is not available until that * time. */ private void createDocument(String namespaceURI, String rootTagName) { if ((fPublicId != null) || (fSystemId != null) || (fInternalSubsetStr != null)) { fXmlcDoc.createDocumentType(fDocTypeName, fPublicId, fSystemId, fInternalSubsetStr); } fDocument = fXmlcDoc.createDocument(namespaceURI, rootTagName); fCurrentNode = fDocument.getDocumentElement(); if (fPendingPreDocument != null) { addPendingPreDocument(); } } /** * Get the document associated with this object. */ public XMLCDocument getDocument() { if (fDocument == null) { throw new XMLCError("XMLC bug: Attempt to get document that hasn;t been created"); } return fXmlcDoc; } /** * Get the node on the top of the stack during parsing. * FIXME: To support the broken swing parser. */ public Node getCurrentNode() { return fCurrentNode; } /** * Pop the current node off of the stack. This is *only* used * during error recover from a broken parser. * FIXME: This and getCurrentNode() should go away when the * with the broken swing parser. */ public void popCurrentNode() { fCurrentNode = fCurrentNode.getParentNode(); } /** * Start a new Element. */ public void startElement(String namespaceURI, String tagName) { if (fDocument == null) { // root (first) element createDocument(namespaceURI, tagName); } else { // non-root element Element element; if (namespaceURI != null) { element = fDocument.createElementNS(namespaceURI, tagName); } else { element = fDocument.createElement(tagName); } fCurrentNode.appendChild(element); fCurrentNode = element; } } /** * Add an attribute to the element on the top of the * stack. */ //FIXME: This doesn't handle attr entity refs public void addAttribute(String namespaceURI, String name, String value) { // Xerces code sezs: DOM Level 2 wants all namespace declaration // attributes to be bound to "http://www.w3.org/2000/xmlns/" So as // long as the XML parser doesn't do it, it needs to done here. if ((namespaceURI == null) || (namespaceURI.length() == 0)) { int prefixIdx = name.indexOf(':'); String prefix = (prefixIdx < 0) ? null : name.substring(0, prefixIdx); if ((prefix != null) && (prefix.equals("xmlns")) || (name.equals("xmlns"))) { namespaceURI = "http://www.w3.org/2000/xmlns/"; } } if (namespaceURI != null) { ((Element)fCurrentNode).setAttributeNS(namespaceURI, name, value); } else { ((Element)fCurrentNode).setAttribute(name, value); } } /** * Finish the element being constructed. */ public void finishElement() { if (fCurrentNode == null) { throw new XMLCError("node stack underflow; malformed document"); } if (!(fCurrentNode instanceof Element)) { throw new XMLCError("DOM node top of stack not a element for end tag"); } fCurrentNode = fCurrentNode.getParentNode(); } /** * Start an entity reference in the document (not DTD). */ public void startEntityReference(String entityName) { if (fDocument == null) { docNotCreatedError(); } EntityReference entityRef = fDocument.createEntityReference(entityName); fCurrentNode.appendChild(entityRef); fCurrentNode = entityRef; } /** * End an entity reference. */ public void endEntityReference() { if (fCurrentNode == null) { throw new XMLCError("node stack underflow; malformed document"); } if (!(fCurrentNode instanceof EntityReference)) { throw new XMLCError("DOM node top of stack not a EntityReference for end tag"); } fCurrentNode = fCurrentNode.getParentNode(); } /** * Add a Text node. */ public void addTextNode(String data) { if (fDocument == null) { docNotCreatedError(); } fCurrentNode.appendChild(fDocument.createTextNode(data)); } /** * Add a Comment node. */ public void addComment(String data) { if (fDocument == null) { holdComment(data); // before first element.. } else { fCurrentNode.appendChild(fDocument.createComment(data)); } } /** * Add a CDATASection node. */ public void addCDATASection(String data) { if (fDocument == null) { docNotCreatedError(); } fCurrentNode.appendChild(fDocument.createCDATASection(data)); } /** * Add a ProcessingInstruction node. */ public void addProcessingInstruction(String target, String data) { if (fDocument == null) { holdProcessingInstruction(target, data); } else { fCurrentNode.appendChild(fDocument.createProcessingInstruction(target, data)); } } /** * Add an EntityReference object. */ public void addEntityReference(String name) { if (fDocument == null) { docNotCreatedError(); } fCurrentNode.appendChild(fDocument.createEntityReference(name)); } /** * Called at the end of parsing, to finish any pending tasks, default * values, etc. */ public void finish() { if (fXmlcDoc.getEncoding() == null) { fXmlcDoc.setEncoding(DEFAULT_XML_ENCODING); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy