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