001: /*
002: * Fast Infoset ver. 0.1 software ("Software")
003: *
004: * Copyright, 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * Software is licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License. You may
008: * obtain a copy of the License at:
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations.
016: *
017: * Sun supports and benefits from the global community of open source
018: * developers, and thanks the community for its important contributions and
019: * open standards-based technology, which Sun has adopted into many of its
020: * products.
021: *
022: * Please note that portions of Software may be provided with notices and
023: * open source licenses from such communities and third parties that govern the
024: * use of those portions, and any licenses granted hereunder do not alter any
025: * rights and obligations you may have under such open source licenses,
026: * however, the disclaimer of warranty and limitation of liability provisions
027: * in this License will apply to all Software in this distribution.
028: *
029: * You acknowledge that the Software is not designed, licensed or intended
030: * for use in the design, construction, operation or maintenance of any nuclear
031: * facility.
032: *
033: * Apache License
034: * Version 2.0, January 2004
035: * http://www.apache.org/licenses/
036: *
037: */
038:
039: package com.sun.xml.fastinfoset.dom;
040:
041: import com.sun.xml.fastinfoset.Encoder;
042: import com.sun.xml.fastinfoset.EncodingConstants;
043: import com.sun.xml.fastinfoset.QualifiedName;
044: import com.sun.xml.fastinfoset.util.NamespaceContextImplementation;
045: import com.sun.xml.fastinfoset.util.LocalNameQualifiedNamesMap;
046: import java.io.IOException;
047: import org.jvnet.fastinfoset.FastInfosetException;
048: import org.w3c.dom.Attr;
049: import org.w3c.dom.Document;
050: import org.w3c.dom.NamedNodeMap;
051: import org.w3c.dom.Node;
052: import org.w3c.dom.NodeList;
053:
054: /**
055: * The Fast Infoset DOM serializer.
056: * <p>
057: * Instantiate this serializer to serialize a fast infoset document in accordance
058: * with the DOM API.
059: *
060: */
061: public class DOMDocumentSerializer extends Encoder {
062:
063: /**
064: * Serialize a {@link Node}.
065: *
066: * @param n the node to serialize.
067: */
068: public final void serialize(Node n) throws IOException {
069: switch (n.getNodeType()) {
070: case Node.DOCUMENT_NODE:
071: serialize((Document) n);
072: break;
073: case Node.ELEMENT_NODE:
074: serializeElementAsDocument(n);
075: break;
076: case Node.COMMENT_NODE:
077: serializeComment(n);
078: break;
079: case Node.PROCESSING_INSTRUCTION_NODE:
080: serializeProcessingInstruction(n);
081: break;
082: }
083: }
084:
085: /**
086: * Serialize a {@link Document}.
087: *
088: * @param d the document to serialize.
089: */
090: public final void serialize(Document d) throws IOException {
091: reset();
092: encodeHeader(false);
093: encodeInitialVocabulary();
094:
095: final NodeList nl = d.getChildNodes();
096: for (int i = 0; i < nl.getLength(); i++) {
097: final Node n = nl.item(i);
098: switch (n.getNodeType()) {
099: case Node.ELEMENT_NODE:
100: serializeElement(n);
101: break;
102: case Node.COMMENT_NODE:
103: serializeComment(n);
104: break;
105: case Node.PROCESSING_INSTRUCTION_NODE:
106: serializeProcessingInstruction(n);
107: break;
108: }
109: }
110: encodeDocumentTermination();
111: }
112:
113: protected final void serializeElementAsDocument(Node e)
114: throws IOException {
115: reset();
116: encodeHeader(false);
117: encodeInitialVocabulary();
118:
119: serializeElement(e);
120:
121: encodeDocumentTermination();
122: }
123:
124: // protected Node[] _namespaceAttributes = new Node[4];
125:
126: // map which will hold all current scope prefixes and associated attributes
127: // Collection of populated namespace available for current scope
128: protected NamespaceContextImplementation _namespaceScopeContext = new NamespaceContextImplementation();
129: protected Node[] _attributes = new Node[32];
130:
131: protected final void serializeElement(Node e) throws IOException {
132: encodeTermination();
133:
134: int attributesSize = 0;
135:
136: _namespaceScopeContext.pushContext();
137:
138: if (e.hasAttributes()) {
139: /*
140: * Split the attribute nodes into namespace attributes
141: * or normal attributes.
142: */
143: final NamedNodeMap nnm = e.getAttributes();
144: for (int i = 0; i < nnm.getLength(); i++) {
145: final Node a = nnm.item(i);
146: final String namespaceURI = a.getNamespaceURI();
147: if (namespaceURI != null
148: && namespaceURI
149: .equals("http://www.w3.org/2000/xmlns/")) {
150: String attrPrefix = a.getLocalName();
151: String attrNamespace = a.getNodeValue();
152: if (attrPrefix == "xmlns"
153: || attrPrefix.equals("xmlns")) {
154: attrPrefix = "";
155: }
156: _namespaceScopeContext.declarePrefix(attrPrefix,
157: attrNamespace);
158: } else {
159: if (attributesSize == _attributes.length) {
160: final Node[] attributes = new Node[attributesSize * 3 / 2 + 1];
161: System.arraycopy(_attributes, 0, attributes, 0,
162: attributesSize);
163: _attributes = attributes;
164: }
165: _attributes[attributesSize++] = a;
166:
167: String attrNamespaceURI = a.getNamespaceURI();
168: String attrPrefix = a.getPrefix();
169: if (attrPrefix != null
170: && !_namespaceScopeContext.getNamespaceURI(
171: attrPrefix)
172: .equals(attrNamespaceURI)) {
173: _namespaceScopeContext.declarePrefix(
174: attrPrefix, attrNamespaceURI);
175: }
176: }
177: }
178: }
179:
180: String elementNamespaceURI = e.getNamespaceURI();
181: String elementPrefix = e.getPrefix();
182: if (elementPrefix == null)
183: elementPrefix = "";
184: if (elementNamespaceURI != null
185: && !_namespaceScopeContext.getNamespaceURI(
186: elementPrefix).equals(elementNamespaceURI)) {
187: _namespaceScopeContext.declarePrefix(elementPrefix,
188: elementNamespaceURI);
189: }
190:
191: if (!_namespaceScopeContext.isCurrentContextEmpty()) {
192: if (attributesSize > 0) {
193: write(EncodingConstants.ELEMENT
194: | EncodingConstants.ELEMENT_NAMESPACES_FLAG
195: | EncodingConstants.ELEMENT_ATTRIBUTE_FLAG);
196: } else {
197: write(EncodingConstants.ELEMENT
198: | EncodingConstants.ELEMENT_NAMESPACES_FLAG);
199: }
200:
201: for (int i = _namespaceScopeContext
202: .getCurrentContextStartIndex(); i < _namespaceScopeContext
203: .getCurrentContextEndIndex(); i++) {
204:
205: String prefix = _namespaceScopeContext.getPrefix(i);
206: String uri = _namespaceScopeContext.getNamespaceURI(i);
207: encodeNamespaceAttribute(prefix, uri);
208: }
209: write(EncodingConstants.TERMINATOR);
210: _b = 0;
211: } else {
212: _b = (attributesSize > 0) ? EncodingConstants.ELEMENT
213: | EncodingConstants.ELEMENT_ATTRIBUTE_FLAG
214: : EncodingConstants.ELEMENT;
215: }
216:
217: String namespaceURI = elementNamespaceURI;
218: // namespaceURI = (namespaceURI == null) ? _namespaceScopeContext.getNamespaceURI("") : namespaceURI;
219: namespaceURI = (namespaceURI == null) ? "" : namespaceURI;
220: encodeElement(namespaceURI, e.getNodeName(), e.getLocalName());
221:
222: if (attributesSize > 0) {
223: // Serialize the attributes
224: for (int i = 0; i < attributesSize; i++) {
225: final Node a = _attributes[i];
226: _attributes[i] = null;
227: namespaceURI = a.getNamespaceURI();
228: namespaceURI = (namespaceURI == null) ? ""
229: : namespaceURI;
230: encodeAttribute(namespaceURI, a.getNodeName(), a
231: .getLocalName());
232:
233: final String value = a.getNodeValue();
234: final boolean addToTable = isAttributeValueLengthMatchesLimit(value
235: .length());
236: encodeNonIdentifyingStringOnFirstBit(value,
237: _v.attributeValue, addToTable);
238: }
239:
240: _b = EncodingConstants.TERMINATOR;
241: _terminate = true;
242: }
243:
244: if (e.hasChildNodes()) {
245: // Serialize the children
246: final NodeList nl = e.getChildNodes();
247: for (int i = 0; i < nl.getLength(); i++) {
248: final Node n = nl.item(i);
249: switch (n.getNodeType()) {
250: case Node.ELEMENT_NODE:
251: serializeElement(n);
252: break;
253: case Node.TEXT_NODE:
254: serializeText(n);
255: break;
256: case Node.CDATA_SECTION_NODE:
257: serializeCDATA(n);
258: break;
259: case Node.COMMENT_NODE:
260: serializeComment(n);
261: break;
262: case Node.PROCESSING_INSTRUCTION_NODE:
263: serializeProcessingInstruction(n);
264: break;
265: }
266: }
267: }
268: encodeElementTermination();
269: _namespaceScopeContext.popContext();
270: }
271:
272: protected final void serializeText(Node t) throws IOException {
273: final String text = t.getNodeValue();
274:
275: final int length = (text != null) ? text.length() : 0;
276: if (length == 0) {
277: return;
278: } else if (length < _charBuffer.length) {
279: text.getChars(0, length, _charBuffer, 0);
280: if (getIgnoreWhiteSpaceTextContent()
281: && isWhiteSpace(_charBuffer, 0, length))
282: return;
283:
284: encodeTermination();
285: encodeCharacters(_charBuffer, 0, length);
286: } else {
287: final char ch[] = text.toCharArray();
288: if (getIgnoreWhiteSpaceTextContent()
289: && isWhiteSpace(ch, 0, length))
290: return;
291:
292: encodeTermination();
293: encodeCharactersNoClone(ch, 0, length);
294: }
295: }
296:
297: protected final void serializeCDATA(Node t) throws IOException {
298: final String text = t.getNodeValue();
299:
300: final int length = (text != null) ? text.length() : 0;
301: if (length == 0) {
302: return;
303: } else {
304: final char ch[] = text.toCharArray();
305: if (getIgnoreWhiteSpaceTextContent()
306: && isWhiteSpace(ch, 0, length))
307: return;
308:
309: encodeTermination();
310: try {
311: encodeCIIBuiltInAlgorithmDataAsCDATA(ch, 0, length);
312: } catch (FastInfosetException e) {
313: throw new IOException("");
314: }
315: }
316: }
317:
318: protected final void serializeComment(Node c) throws IOException {
319: if (getIgnoreComments())
320: return;
321:
322: encodeTermination();
323:
324: final String comment = c.getNodeValue();
325:
326: final int length = (comment != null) ? comment.length() : 0;
327: if (length == 0) {
328: encodeComment(_charBuffer, 0, 0);
329: } else if (length < _charBuffer.length) {
330: comment.getChars(0, length, _charBuffer, 0);
331: encodeComment(_charBuffer, 0, length);
332: } else {
333: final char ch[] = comment.toCharArray();
334: encodeCommentNoClone(ch, 0, length);
335: }
336: }
337:
338: protected final void serializeProcessingInstruction(Node pi)
339: throws IOException {
340: if (getIgnoreProcesingInstructions())
341: return;
342:
343: encodeTermination();
344:
345: final String target = pi.getNodeName();
346: final String data = pi.getNodeValue();
347: encodeProcessingInstruction(target, data);
348: }
349:
350: protected final void encodeElement(String namespaceURI,
351: String qName, String localName) throws IOException {
352: LocalNameQualifiedNamesMap.Entry entry = _v.elementName
353: .obtainEntry(qName);
354: if (entry._valueIndex > 0) {
355: final QualifiedName[] names = entry._value;
356: for (int i = 0; i < entry._valueIndex; i++) {
357: if ((namespaceURI == names[i].namespaceName || namespaceURI
358: .equals(names[i].namespaceName))) {
359: encodeNonZeroIntegerOnThirdBit(names[i].index);
360: return;
361: }
362: }
363: }
364:
365: // Was DOM node created using an NS-aware call?
366: if (localName != null) {
367: encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI,
368: getPrefixFromQualifiedName(qName), localName, entry);
369: } else {
370: encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI,
371: "", qName, entry);
372: }
373: }
374:
375: protected final void encodeAttribute(String namespaceURI,
376: String qName, String localName) throws IOException {
377: LocalNameQualifiedNamesMap.Entry entry = _v.attributeName
378: .obtainEntry(qName);
379: if (entry._valueIndex > 0) {
380: final QualifiedName[] names = entry._value;
381: for (int i = 0; i < entry._valueIndex; i++) {
382: if ((namespaceURI == names[i].namespaceName || namespaceURI
383: .equals(names[i].namespaceName))) {
384: encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index);
385: return;
386: }
387: }
388: }
389:
390: // Was DOM node created using an NS-aware call?
391: if (localName != null) {
392: encodeLiteralAttributeQualifiedNameOnSecondBit(
393: namespaceURI, getPrefixFromQualifiedName(qName),
394: localName, entry);
395: } else {
396: encodeLiteralAttributeQualifiedNameOnSecondBit(
397: namespaceURI, "", qName, entry);
398: }
399: }
400: }
|