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