1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.jaxp.validation;
  22 
  23 import java.util.ArrayList;
  24 
  25 import javax.xml.transform.dom.DOMResult;
  26 
  27 import com.sun.org.apache.xerces.internal.dom.AttrImpl;
  28 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
  29 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  30 import com.sun.org.apache.xerces.internal.dom.DocumentTypeImpl;
  31 import com.sun.org.apache.xerces.internal.dom.ElementImpl;
  32 import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;
  33 import com.sun.org.apache.xerces.internal.dom.EntityImpl;
  34 import com.sun.org.apache.xerces.internal.dom.NotationImpl;
  35 import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
  36 import com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl;
  37 import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
  38 import com.sun.org.apache.xerces.internal.impl.Constants;
  39 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  40 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  41 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  42 import com.sun.org.apache.xerces.internal.xni.QName;
  43 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  44 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  45 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  46 import com.sun.org.apache.xerces.internal.xni.XMLString;
  47 import com.sun.org.apache.xerces.internal.xni.XNIException;
  48 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  49 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  50 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  51 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  52 
  53 import org.w3c.dom.CDATASection;
  54 import org.w3c.dom.Comment;
  55 import org.w3c.dom.Document;
  56 import org.w3c.dom.DocumentType;
  57 import org.w3c.dom.Element;
  58 import org.w3c.dom.Entity;
  59 import org.w3c.dom.NamedNodeMap;
  60 import org.w3c.dom.Node;
  61 import org.w3c.dom.Notation;
  62 import org.w3c.dom.ProcessingInstruction;
  63 import org.w3c.dom.Text;
  64 
  65 
  66 /**
  67  * <p>DOM result builder.</p>
  68  *
  69  * @author Michael Glavassevich, IBM
  70  */
  71 final class DOMResultBuilder implements DOMDocumentHandler {
  72 
  73     /** Table for quick check of child insertion. */
  74     private final static int[] kidOK;
  75 
  76     static {
  77         kidOK = new int[13];
  78         kidOK[Node.DOCUMENT_NODE] =
  79             1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE |
  80             1 << Node.COMMENT_NODE | 1 << Node.DOCUMENT_TYPE_NODE;
  81         kidOK[Node.DOCUMENT_FRAGMENT_NODE] =
  82         kidOK[Node.ENTITY_NODE] =
  83         kidOK[Node.ENTITY_REFERENCE_NODE] =
  84         kidOK[Node.ELEMENT_NODE] =
  85             1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE |
  86             1 << Node.COMMENT_NODE | 1 << Node.TEXT_NODE |
  87             1 << Node.CDATA_SECTION_NODE | 1 << Node.ENTITY_REFERENCE_NODE ;
  88         kidOK[Node.ATTRIBUTE_NODE] = 1 << Node.TEXT_NODE | 1 << Node.ENTITY_REFERENCE_NODE;
  89         kidOK[Node.DOCUMENT_TYPE_NODE] = 0;
  90         kidOK[Node.PROCESSING_INSTRUCTION_NODE] = 0;
  91         kidOK[Node.COMMENT_NODE] = 0;
  92         kidOK[Node.TEXT_NODE] = 0;
  93         kidOK[Node.CDATA_SECTION_NODE] = 0;
  94         kidOK[Node.NOTATION_NODE] = 0;
  95     } // static
  96 
  97     //
  98     // Data
  99     //
 100 
 101     private Document fDocument;
 102     private CoreDocumentImpl fDocumentImpl;
 103     private boolean fStorePSVI;
 104 
 105     private Node fTarget;
 106     private Node fNextSibling;
 107 
 108     private Node fCurrentNode;
 109     private Node fFragmentRoot;
 110 
 111     private final ArrayList fTargetChildren = new ArrayList();
 112 
 113     private boolean fIgnoreChars;
 114 
 115     private final QName fAttributeQName = new QName();
 116 
 117     public DOMResultBuilder() {}
 118 
 119     /*
 120      * DOMDocumentHandler methods
 121      */
 122 
 123     public void setDOMResult(DOMResult result) {
 124         fCurrentNode = null;
 125         fFragmentRoot = null;
 126         fIgnoreChars = false;
 127         fTargetChildren.clear();
 128         if (result != null) {
 129             fTarget = result.getNode();
 130             fNextSibling = result.getNextSibling();
 131             fDocument = (fTarget.getNodeType() == Node.DOCUMENT_NODE) ? (Document) fTarget : fTarget.getOwnerDocument();
 132             fDocumentImpl = (fDocument instanceof CoreDocumentImpl) ? (CoreDocumentImpl) fDocument : null;
 133             fStorePSVI = (fDocument instanceof PSVIDocumentImpl);
 134             return;
 135         }
 136         fTarget = null;
 137         fNextSibling = null;
 138         fDocument = null;
 139         fDocumentImpl = null;
 140         fStorePSVI = false;
 141     }
 142 
 143     public void doctypeDecl(DocumentType node) throws XNIException {
 144         /** Create new DocumentType node for the target. */
 145         if (fDocumentImpl != null) {
 146             DocumentType docType = fDocumentImpl.createDocumentType(node.getName(), node.getPublicId(), node.getSystemId());
 147             final String internalSubset = node.getInternalSubset();
 148             /** Copy internal subset. */
 149             if (internalSubset != null) {
 150                 ((DocumentTypeImpl) docType).setInternalSubset(internalSubset);
 151             }
 152             /** Copy entities. */
 153             NamedNodeMap oldMap = node.getEntities();
 154             NamedNodeMap newMap = docType.getEntities();
 155             int length = oldMap.getLength();
 156             for (int i = 0; i < length; ++i) {
 157                 Entity oldEntity = (Entity) oldMap.item(i);
 158                 EntityImpl newEntity = (EntityImpl) fDocumentImpl.createEntity(oldEntity.getNodeName());
 159                 newEntity.setPublicId(oldEntity.getPublicId());
 160                 newEntity.setSystemId(oldEntity.getSystemId());
 161                 newEntity.setNotationName(oldEntity.getNotationName());
 162                 newMap.setNamedItem(newEntity);
 163             }
 164             /** Copy notations. */
 165             oldMap = node.getNotations();
 166             newMap = docType.getNotations();
 167             length = oldMap.getLength();
 168             for (int i = 0; i < length; ++i) {
 169                 Notation oldNotation = (Notation) oldMap.item(i);
 170                 NotationImpl newNotation = (NotationImpl) fDocumentImpl.createNotation(oldNotation.getNodeName());
 171                 newNotation.setPublicId(oldNotation.getPublicId());
 172                 newNotation.setSystemId(oldNotation.getSystemId());
 173                 newMap.setNamedItem(newNotation);
 174             }
 175             append(docType);
 176         }
 177     }
 178 
 179     public void characters(Text node) throws XNIException {
 180         /** Create new Text node for the target. */
 181         append(fDocument.createTextNode(node.getNodeValue()));
 182     }
 183 
 184     public void cdata(CDATASection node) throws XNIException {
 185         /** Create new CDATASection node for the target. */
 186         append(fDocument.createCDATASection(node.getNodeValue()));
 187     }
 188 
 189     public void comment(Comment node) throws XNIException {
 190         /** Create new Comment node for the target. */
 191         append(fDocument.createComment(node.getNodeValue()));
 192     }
 193 
 194     public void processingInstruction(ProcessingInstruction node)
 195             throws XNIException {
 196         /** Create new ProcessingInstruction node for the target. */
 197         append(fDocument.createProcessingInstruction(node.getTarget(), node.getData()));
 198     }
 199 
 200     public void setIgnoringCharacters(boolean ignore) {
 201         fIgnoreChars = ignore;
 202     }
 203 
 204     /*
 205      * XMLDocumentHandler methods
 206      */
 207 
 208     public void startDocument(XMLLocator locator, String encoding,
 209             NamespaceContext namespaceContext, Augmentations augs)
 210             throws XNIException {}
 211 
 212     public void xmlDecl(String version, String encoding, String standalone,
 213             Augmentations augs) throws XNIException {}
 214 
 215     public void doctypeDecl(String rootElement, String publicId,
 216             String systemId, Augmentations augs) throws XNIException {}
 217 
 218     public void comment(XMLString text, Augmentations augs) throws XNIException {}
 219 
 220     public void processingInstruction(String target, XMLString data,
 221             Augmentations augs) throws XNIException {}
 222 
 223     public void startElement(QName element, XMLAttributes attributes,
 224             Augmentations augs) throws XNIException {
 225         Element elem;
 226         int attrCount = attributes.getLength();
 227         if (fDocumentImpl == null) {
 228             elem = fDocument.createElementNS(element.uri, element.rawname);
 229             for (int i = 0; i < attrCount; ++i) {
 230                 attributes.getName(i, fAttributeQName);
 231                 elem.setAttributeNS(fAttributeQName.uri, fAttributeQName.rawname, attributes.getValue(i));
 232             }
 233         }
 234         // If it's a Xerces DOM store type information for attributes, set idness, etc..
 235         else {
 236             elem = fDocumentImpl.createElementNS(element.uri, element.rawname, element.localpart);
 237             for (int i = 0; i < attrCount; ++i) {
 238                 attributes.getName(i, fAttributeQName);
 239                 AttrImpl attr = (AttrImpl) fDocumentImpl.createAttributeNS(fAttributeQName.uri,
 240                         fAttributeQName.rawname, fAttributeQName.localpart);
 241                 attr.setValue(attributes.getValue(i));
 242 
 243                 // write type information to this attribute
 244                 AttributePSVI attrPSVI = (AttributePSVI) attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_PSVI);
 245                 if (attrPSVI != null) {
 246                     if (fStorePSVI) {
 247                         ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI);
 248                     }
 249                     Object type = attrPSVI.getMemberTypeDefinition();
 250                     if (type == null) {
 251                         type = attrPSVI.getTypeDefinition();
 252                         if (type != null) {
 253                             attr.setType (type);
 254                             if (((XSSimpleType) type).isIDType()) {
 255                                 ((ElementImpl) elem).setIdAttributeNode (attr, true);
 256                             }
 257                         }
 258                     }
 259                     else {
 260                         attr.setType (type);
 261                         if (((XSSimpleType) type).isIDType()) {
 262                             ((ElementImpl) elem).setIdAttributeNode (attr, true);
 263                         }
 264                     }
 265                 }
 266                 attr.setSpecified(attributes.isSpecified(i));
 267                 elem.setAttributeNode(attr);
 268             }
 269         }
 270         append(elem);
 271         fCurrentNode = elem;
 272         if (fFragmentRoot == null) {
 273             fFragmentRoot = elem;
 274         }
 275     }
 276 
 277     public void emptyElement(QName element, XMLAttributes attributes,
 278             Augmentations augs) throws XNIException {
 279         startElement(element, attributes, augs);
 280         endElement(element, augs);
 281     }
 282 
 283     public void startGeneralEntity(String name,
 284             XMLResourceIdentifier identifier, String encoding,
 285             Augmentations augs) throws XNIException {}
 286 
 287     public void textDecl(String version, String encoding, Augmentations augs)
 288             throws XNIException {}
 289 
 290     public void endGeneralEntity(String name, Augmentations augs)
 291             throws XNIException {}
 292 
 293     public void characters(XMLString text, Augmentations augs)
 294             throws XNIException {
 295         if (!fIgnoreChars) {
 296             append(fDocument.createTextNode(text.toString()));
 297         }
 298     }
 299 
 300     public void ignorableWhitespace(XMLString text, Augmentations augs)
 301             throws XNIException {
 302         characters(text, augs);
 303     }
 304 
 305     public void endElement(QName element, Augmentations augs)
 306             throws XNIException {
 307         // write type information to this element
 308         if (augs != null && fDocumentImpl != null) {
 309             ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI);
 310             if (elementPSVI != null) {
 311                 if (fStorePSVI) {
 312                     ((PSVIElementNSImpl)fCurrentNode).setPSVI(elementPSVI);
 313                 }
 314                 XSTypeDefinition type = elementPSVI.getMemberTypeDefinition();
 315                 if (type == null) {
 316                     type = elementPSVI.getTypeDefinition();
 317                 }
 318                 ((ElementNSImpl)fCurrentNode).setType(type);
 319             }
 320         }
 321 
 322         // adjust current node reference
 323         if (fCurrentNode == fFragmentRoot) {
 324             fCurrentNode = null;
 325             fFragmentRoot = null;
 326             return;
 327         }
 328         fCurrentNode = fCurrentNode.getParentNode();
 329     }
 330 
 331     public void startCDATA(Augmentations augs) throws XNIException {}
 332 
 333     public void endCDATA(Augmentations augs) throws XNIException {}
 334 
 335     public void endDocument(Augmentations augs) throws XNIException {
 336         final int length = fTargetChildren.size();
 337         if (fNextSibling == null) {
 338             for (int i = 0; i < length; ++i) {
 339                 fTarget.appendChild((Node) fTargetChildren.get(i));
 340             }
 341         }
 342         else {
 343             for (int i = 0; i < length; ++i) {
 344                 fTarget.insertBefore((Node) fTargetChildren.get(i), fNextSibling);
 345             }
 346         }
 347     }
 348 
 349     public void setDocumentSource(XMLDocumentSource source) {}
 350 
 351     public XMLDocumentSource getDocumentSource() {
 352         return null;
 353     }
 354 
 355     /*
 356      * Other methods
 357      */
 358 
 359     private void append(Node node) throws XNIException {
 360         if (fCurrentNode != null) {
 361             fCurrentNode.appendChild(node);
 362         }
 363         else {
 364             /** Check if this node can be attached to the target. */
 365             if ((kidOK[fTarget.getNodeType()] & (1 << node.getNodeType())) == 0) {
 366                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
 367                 throw new XNIException(msg);
 368             }
 369             fTargetChildren.add(node);
 370         }
 371     }
 372 
 373 } // DOMResultBuilder