001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.jaxp.validation;
019:
020: import java.util.ArrayList;
021:
022: import javax.xml.transform.dom.DOMResult;
023:
024: import org.apache.xerces.dom.AttrImpl;
025: import org.apache.xerces.dom.CoreDocumentImpl;
026: import org.apache.xerces.dom.DOMMessageFormatter;
027: import org.apache.xerces.dom.DocumentTypeImpl;
028: import org.apache.xerces.dom.ElementImpl;
029: import org.apache.xerces.dom.ElementNSImpl;
030: import org.apache.xerces.dom.EntityImpl;
031: import org.apache.xerces.dom.NotationImpl;
032: import org.apache.xerces.dom.PSVIAttrNSImpl;
033: import org.apache.xerces.dom.PSVIDocumentImpl;
034: import org.apache.xerces.dom.PSVIElementNSImpl;
035: import org.apache.xerces.impl.Constants;
036: import org.apache.xerces.impl.dv.XSSimpleType;
037: import org.apache.xerces.xni.Augmentations;
038: import org.apache.xerces.xni.NamespaceContext;
039: import org.apache.xerces.xni.QName;
040: import org.apache.xerces.xni.XMLAttributes;
041: import org.apache.xerces.xni.XMLLocator;
042: import org.apache.xerces.xni.XMLResourceIdentifier;
043: import org.apache.xerces.xni.XMLString;
044: import org.apache.xerces.xni.XNIException;
045: import org.apache.xerces.xni.parser.XMLDocumentSource;
046: import org.apache.xerces.xs.AttributePSVI;
047: import org.apache.xerces.xs.ElementPSVI;
048: import org.apache.xerces.xs.XSTypeDefinition;
049:
050: import org.w3c.dom.CDATASection;
051: import org.w3c.dom.Comment;
052: import org.w3c.dom.Document;
053: import org.w3c.dom.DocumentType;
054: import org.w3c.dom.Element;
055: import org.w3c.dom.Entity;
056: import org.w3c.dom.NamedNodeMap;
057: import org.w3c.dom.Node;
058: import org.w3c.dom.Notation;
059: import org.w3c.dom.ProcessingInstruction;
060: import org.w3c.dom.Text;
061:
062: /**
063: * <p>DOM result builder.</p>
064: *
065: * @author Michael Glavassevich, IBM
066: * @version $Id: DOMResultBuilder.java 476292 2006-11-17 20:09:26Z mrglavas $
067: */
068: final class DOMResultBuilder implements DOMDocumentHandler {
069:
070: /** Table for quick check of child insertion. */
071: private final static int[] kidOK;
072:
073: static {
074: kidOK = new int[13];
075: kidOK[Node.DOCUMENT_NODE] = 1 << Node.ELEMENT_NODE
076: | 1 << Node.PROCESSING_INSTRUCTION_NODE
077: | 1 << Node.COMMENT_NODE | 1 << Node.DOCUMENT_TYPE_NODE;
078: kidOK[Node.DOCUMENT_FRAGMENT_NODE] = kidOK[Node.ENTITY_NODE] = kidOK[Node.ENTITY_REFERENCE_NODE] = kidOK[Node.ELEMENT_NODE] = 1 << Node.ELEMENT_NODE
079: | 1 << Node.PROCESSING_INSTRUCTION_NODE
080: | 1 << Node.COMMENT_NODE
081: | 1 << Node.TEXT_NODE
082: | 1 << Node.CDATA_SECTION_NODE
083: | 1 << Node.ENTITY_REFERENCE_NODE;
084: kidOK[Node.ATTRIBUTE_NODE] = 1 << Node.TEXT_NODE
085: | 1 << Node.ENTITY_REFERENCE_NODE;
086: kidOK[Node.DOCUMENT_TYPE_NODE] = 0;
087: kidOK[Node.PROCESSING_INSTRUCTION_NODE] = 0;
088: kidOK[Node.COMMENT_NODE] = 0;
089: kidOK[Node.TEXT_NODE] = 0;
090: kidOK[Node.CDATA_SECTION_NODE] = 0;
091: kidOK[Node.NOTATION_NODE] = 0;
092: } // static
093:
094: //
095: // Data
096: //
097:
098: private Document fDocument;
099: private CoreDocumentImpl fDocumentImpl;
100: private boolean fStorePSVI;
101:
102: private Node fTarget;
103: private Node fNextSibling;
104:
105: private Node fCurrentNode;
106: private Node fFragmentRoot;
107:
108: private final ArrayList fTargetChildren = new ArrayList();
109:
110: private boolean fIgnoreChars;
111:
112: private final QName fAttributeQName = new QName();
113:
114: public DOMResultBuilder() {
115: }
116:
117: /*
118: * DOMDocumentHandler methods
119: */
120:
121: public void setDOMResult(DOMResult result) {
122: fCurrentNode = null;
123: fFragmentRoot = null;
124: fIgnoreChars = false;
125: fTargetChildren.clear();
126: if (result != null) {
127: fTarget = result.getNode();
128: fNextSibling = result.getNextSibling();
129: fDocument = (fTarget.getNodeType() == Node.DOCUMENT_NODE) ? (Document) fTarget
130: : fTarget.getOwnerDocument();
131: fDocumentImpl = (fDocument instanceof CoreDocumentImpl) ? (CoreDocumentImpl) fDocument
132: : 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(
147: node.getName(), node.getPublicId(), node
148: .getSystemId());
149: final String internalSubset = node.getInternalSubset();
150: /** Copy internal subset. */
151: if (internalSubset != null) {
152: ((DocumentTypeImpl) docType)
153: .setInternalSubset(internalSubset);
154: }
155: /** Copy entities. */
156: NamedNodeMap oldMap = node.getEntities();
157: NamedNodeMap newMap = docType.getEntities();
158: int length = oldMap.getLength();
159: for (int i = 0; i < length; ++i) {
160: Entity oldEntity = (Entity) oldMap.item(i);
161: EntityImpl newEntity = (EntityImpl) fDocumentImpl
162: .createEntity(oldEntity.getNodeName());
163: newEntity.setPublicId(oldEntity.getPublicId());
164: newEntity.setSystemId(oldEntity.getSystemId());
165: newEntity.setNotationName(oldEntity.getNotationName());
166: newMap.setNamedItem(newEntity);
167: }
168: /** Copy notations. */
169: oldMap = node.getNotations();
170: newMap = docType.getNotations();
171: length = oldMap.getLength();
172: for (int i = 0; i < length; ++i) {
173: Notation oldNotation = (Notation) oldMap.item(i);
174: NotationImpl newNotation = (NotationImpl) fDocumentImpl
175: .createNotation(oldNotation.getNodeName());
176: newNotation.setPublicId(oldNotation.getPublicId());
177: newNotation.setSystemId(oldNotation.getSystemId());
178: newMap.setNamedItem(newNotation);
179: }
180: append(docType);
181: }
182: }
183:
184: public void characters(Text node) throws XNIException {
185: /** Create new Text node for the target. */
186: append(fDocument.createTextNode(node.getNodeValue()));
187: }
188:
189: public void cdata(CDATASection node) throws XNIException {
190: /** Create new CDATASection node for the target. */
191: append(fDocument.createCDATASection(node.getNodeValue()));
192: }
193:
194: public void comment(Comment node) throws XNIException {
195: /** Create new Comment node for the target. */
196: append(fDocument.createComment(node.getNodeValue()));
197: }
198:
199: public void processingInstruction(ProcessingInstruction node)
200: throws XNIException {
201: /** Create new ProcessingInstruction node for the target. */
202: append(fDocument.createProcessingInstruction(node.getTarget(),
203: node.getData()));
204: }
205:
206: public void setIgnoringCharacters(boolean ignore) {
207: fIgnoreChars = ignore;
208: }
209:
210: /*
211: * XMLDocumentHandler methods
212: */
213:
214: public void startDocument(XMLLocator locator, String encoding,
215: NamespaceContext namespaceContext, Augmentations augs)
216: throws XNIException {
217: }
218:
219: public void xmlDecl(String version, String encoding,
220: String standalone, Augmentations augs) throws XNIException {
221: }
222:
223: public void doctypeDecl(String rootElement, String publicId,
224: String systemId, Augmentations augs) throws XNIException {
225: }
226:
227: public void comment(XMLString text, Augmentations augs)
228: throws XNIException {
229: }
230:
231: public void processingInstruction(String target, XMLString data,
232: Augmentations augs) throws XNIException {
233: }
234:
235: public void startElement(QName element, XMLAttributes attributes,
236: Augmentations augs) throws XNIException {
237: Element elem;
238: int attrCount = attributes.getLength();
239: if (fDocumentImpl == null) {
240: elem = fDocument.createElementNS(element.uri,
241: element.rawname);
242: for (int i = 0; i < attrCount; ++i) {
243: attributes.getName(i, fAttributeQName);
244: elem
245: .setAttributeNS(fAttributeQName.uri,
246: fAttributeQName.rawname, attributes
247: .getValue(i));
248: }
249: }
250: // If it's a Xerces DOM store type information for attributes, set idness, etc..
251: else {
252: elem = fDocumentImpl.createElementNS(element.uri,
253: element.rawname, element.localpart);
254: for (int i = 0; i < attrCount; ++i) {
255: attributes.getName(i, fAttributeQName);
256: AttrImpl attr = (AttrImpl) fDocumentImpl
257: .createAttributeNS(fAttributeQName.uri,
258: fAttributeQName.rawname,
259: fAttributeQName.localpart);
260: attr.setValue(attributes.getValue(i));
261: elem.setAttributeNodeNS(attr);
262:
263: // write type information to this attribute
264: AttributePSVI attrPSVI = (AttributePSVI) attributes
265: .getAugmentations(i).getItem(
266: Constants.ATTRIBUTE_PSVI);
267: if (attrPSVI != null) {
268: if (fStorePSVI) {
269: ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI);
270: }
271: Object type = attrPSVI.getMemberTypeDefinition();
272: if (type == null) {
273: type = attrPSVI.getTypeDefinition();
274: if (type != null) {
275: attr.setType(type);
276: if (((XSSimpleType) type).isIDType()) {
277: ((ElementImpl) elem)
278: .setIdAttributeNode(attr, true);
279: }
280: }
281: } else {
282: attr.setType(type);
283: if (((XSSimpleType) type).isIDType()) {
284: ((ElementImpl) elem).setIdAttributeNode(
285: attr, true);
286: }
287: }
288: }
289: attr.setSpecified(attributes.isSpecified(i));
290: }
291: }
292: append(elem);
293: fCurrentNode = elem;
294: if (fFragmentRoot == null) {
295: fFragmentRoot = elem;
296: }
297: }
298:
299: public void emptyElement(QName element, XMLAttributes attributes,
300: Augmentations augs) throws XNIException {
301: startElement(element, attributes, augs);
302: endElement(element, augs);
303: }
304:
305: public void startGeneralEntity(String name,
306: XMLResourceIdentifier identifier, String encoding,
307: Augmentations augs) throws XNIException {
308: }
309:
310: public void textDecl(String version, String encoding,
311: Augmentations augs) throws XNIException {
312: }
313:
314: public void endGeneralEntity(String name, Augmentations augs)
315: throws XNIException {
316: }
317:
318: public void characters(XMLString text, Augmentations augs)
319: throws XNIException {
320: if (!fIgnoreChars) {
321: append(fDocument.createTextNode(text.toString()));
322: }
323: }
324:
325: public void ignorableWhitespace(XMLString text, Augmentations augs)
326: throws XNIException {
327: characters(text, augs);
328: }
329:
330: public void endElement(QName element, Augmentations augs)
331: throws XNIException {
332: // write type information to this element
333: if (augs != null && fDocumentImpl != null) {
334: ElementPSVI elementPSVI = (ElementPSVI) augs
335: .getItem(Constants.ELEMENT_PSVI);
336: if (elementPSVI != null) {
337: if (fStorePSVI) {
338: ((PSVIElementNSImpl) fCurrentNode)
339: .setPSVI(elementPSVI);
340: }
341: XSTypeDefinition type = elementPSVI
342: .getMemberTypeDefinition();
343: if (type == null) {
344: type = elementPSVI.getTypeDefinition();
345: }
346: ((ElementNSImpl) fCurrentNode).setType(type);
347: }
348: }
349:
350: // adjust current node reference
351: if (fCurrentNode == fFragmentRoot) {
352: fCurrentNode = null;
353: fFragmentRoot = null;
354: return;
355: }
356: fCurrentNode = fCurrentNode.getParentNode();
357: }
358:
359: public void startCDATA(Augmentations augs) throws XNIException {
360: }
361:
362: public void endCDATA(Augmentations augs) throws XNIException {
363: }
364:
365: public void endDocument(Augmentations augs) throws XNIException {
366: final int length = fTargetChildren.size();
367: if (fNextSibling == null) {
368: for (int i = 0; i < length; ++i) {
369: fTarget.appendChild((Node) fTargetChildren.get(i));
370: }
371: } else {
372: for (int i = 0; i < length; ++i) {
373: fTarget.insertBefore((Node) fTargetChildren.get(i),
374: fNextSibling);
375: }
376: }
377: }
378:
379: public void setDocumentSource(XMLDocumentSource source) {
380: }
381:
382: public XMLDocumentSource getDocumentSource() {
383: return null;
384: }
385:
386: /*
387: * Other methods
388: */
389:
390: private void append(Node node) throws XNIException {
391: if (fCurrentNode != null) {
392: fCurrentNode.appendChild(node);
393: } else {
394: /** Check if this node can be attached to the target. */
395: if ((kidOK[fTarget.getNodeType()] & (1 << node
396: .getNodeType())) == 0) {
397: String msg = DOMMessageFormatter.formatMessage(
398: DOMMessageFormatter.DOM_DOMAIN,
399: "HIERARCHY_REQUEST_ERR", null);
400: throw new XNIException(msg);
401: }
402: fTargetChildren.add(node);
403: }
404: }
405:
406: } // DOMResultBuilder
|