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
22package com.sun.org.apache.xerces.internal.jaxp.validation;
23
24import java.util.ArrayList;
25
26import javax.xml.transform.dom.DOMResult;
27
28import com.sun.org.apache.xerces.internal.dom.AttrImpl;
29import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
30import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
31import com.sun.org.apache.xerces.internal.dom.DocumentTypeImpl;
32import com.sun.org.apache.xerces.internal.dom.ElementImpl;
33import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;
34import com.sun.org.apache.xerces.internal.dom.EntityImpl;
35import com.sun.org.apache.xerces.internal.dom.NotationImpl;
36import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
37import com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl;
38import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
39import com.sun.org.apache.xerces.internal.impl.Constants;
40import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
41import com.sun.org.apache.xerces.internal.xni.Augmentations;
42import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
43import com.sun.org.apache.xerces.internal.xni.QName;
44import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
45import com.sun.org.apache.xerces.internal.xni.XMLLocator;
46import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
47import com.sun.org.apache.xerces.internal.xni.XMLString;
48import com.sun.org.apache.xerces.internal.xni.XNIException;
49import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
50import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
51import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
52import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
53
54import org.w3c.dom.CDATASection;
55import org.w3c.dom.Comment;
56import org.w3c.dom.Document;
57import org.w3c.dom.DocumentType;
58import org.w3c.dom.Element;
59import org.w3c.dom.Entity;
60import org.w3c.dom.NamedNodeMap;
61import org.w3c.dom.Node;
62import org.w3c.dom.Notation;
63import org.w3c.dom.ProcessingInstruction;
64import org.w3c.dom.Text;
65
66
67/**
68 * <p>DOM result builder.</p>
69 *
70 * @author Michael Glavassevich, IBM
71 */
72final 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
375