Source Code Cross Referenced for ComplexContentOutputter.java in  » XML » saxonb » net » sf » saxon » event » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML » saxonb » net.sf.saxon.event 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package net.sf.saxon.event;
002:
003:        import net.sf.saxon.expr.ExpressionLocation;
004:        import net.sf.saxon.om.*;
005:        import net.sf.saxon.trans.DynamicError;
006:        import net.sf.saxon.trans.XPathException;
007:        import net.sf.saxon.type.Type;
008:        import net.sf.saxon.value.AtomicValue;
009:        import net.sf.saxon.Configuration;
010:        import net.sf.saxon.Err;
011:
012:        /**
013:         * This class is used for generating complex content, that is, the content of an
014:         * element or document node. It enforces the rules on the order of events within
015:         * complex content (attributes and namespaces must come first), and it implements
016:         * part of the namespace fixup rules, in particular, it ensures that there is a
017:         * namespace node for the namespace used in the element name and in each attribute
018:         * name.
019:         *
020:         * <p>The same ComplexContentOutputter may be used for generating an entire XML
021:         * document; it is not necessary to create a new outputter for each element node.</p>
022:         *
023:         * @author Michael H. Kay
024:         */
025:
026:        public final class ComplexContentOutputter extends SequenceReceiver {
027:
028:            private NamePool pool;
029:            private Receiver receiver;
030:            // the next receiver in the output pipeline
031:
032:            private int pendingStartTag = -2;
033:            // -2 means we are at the top level, or immediately within a document node
034:            // -1 means we are in the content of an element node whose start tag is complete
035:            private int level = -1; // records the number of startDocument or startElement events
036:            // that have not yet been closed. Note that startDocument and startElement
037:            // events may be arbitrarily nested; startDocument and endDocument
038:            // are ignore unless they occur at the outermost level.
039:            private Boolean elementIsInNullNamespace;
040:            private int[] pendingAttCode = new int[20];
041:            private int[] pendingAttType = new int[20];
042:            private CharSequence[] pendingAttValue = new String[20];
043:            private int[] pendingAttLocation = new int[20];
044:            private int[] pendingAttProp = new int[20];
045:            private int pendingAttListSize = 0;
046:
047:            private int[] pendingNSList = new int[20];
048:            private int pendingNSListSize = 0;
049:
050:            private int currentSimpleType = -1; // any other value means we are currently writing an
051:            // element of a particular simple type
052:
053:            private int startElementProperties;
054:            private int startElementLocationId;
055:            private boolean declaresDefaultNamespace;
056:            private boolean allowDuplicateAttributes;
057:
058:            public ComplexContentOutputter() {
059:            }
060:
061:            public void setPipelineConfiguration(
062:                    PipelineConfiguration pipelineConfiguration) {
063:                super .setPipelineConfiguration(pipelineConfiguration);
064:                allowDuplicateAttributes = pipelineConfiguration
065:                        .getController().getExecutable().getHostLanguage() == Configuration.XSLT;
066:            }
067:
068:            public NamePool getNamePool() {
069:                if (pool == null) {
070:                    pool = super .getNamePool();
071:                }
072:                return pool;
073:            }
074:
075:            public void setSystemId(String systemId) {
076:            }
077:
078:            public String getSystemId() {
079:                return null;
080:            }
081:
082:            /**
083:             * Set the receiver (to handle the next stage in the pipeline) directly
084:             */
085:
086:            public void setReceiver(Receiver receiver) {
087:                this .receiver = receiver;
088:            }
089:
090:            /**
091:             * Start the output process
092:             */
093:
094:            public void open() throws XPathException {
095:                receiver.open();
096:                previousAtomic = false;
097:            }
098:
099:            /**
100:             * Start of a document node.
101:             */
102:
103:            public void startDocument(int properties) throws XPathException {
104:                level++;
105:                if (level == 0) {
106:                    receiver.startDocument(properties);
107:                } else if (pendingStartTag >= 0) {
108:                    startContent();
109:                    pendingStartTag = -2;
110:                }
111:                previousAtomic = false;
112:            }
113:
114:            /**
115:             * Notify the end of a document node
116:             */
117:
118:            public void endDocument() throws XPathException {
119:                if (level == 0) {
120:                    receiver.endDocument();
121:                }
122:                level--;
123:            }
124:
125:            /**
126:             * Produce text content output. <BR>
127:             * Special characters are escaped using XML/HTML conventions if the output format
128:             * requires it.
129:             * @param s The String to be output
130:             * @exception XPathException for any failure
131:             */
132:
133:            public void characters(CharSequence s, int locationId,
134:                    int properties) throws XPathException {
135:                previousAtomic = false;
136:                if (s == null)
137:                    return;
138:                int len = s.length();
139:                if (len == 0)
140:                    return;
141:                if (pendingStartTag >= 0) {
142:                    startContent();
143:                }
144:                receiver.characters(s, locationId, properties);
145:            }
146:
147:            /**
148:             * Output an element start tag. <br>
149:             * The actual output of the tag is deferred until all attributes have been output
150:             * using attribute().
151:             * @param nameCode The element name code
152:             */
153:
154:            public void startElement(int nameCode, int typeCode,
155:                    int locationId, int properties) throws XPathException {
156:                // System.err.println("StartElement " + nameCode);
157:                level++;
158:
159:                if (pendingStartTag >= 0) {
160:                    startContent();
161:                }
162:                startElementProperties = properties;
163:                startElementLocationId = locationId;
164:                pendingAttListSize = 0;
165:                pendingNSListSize = 0;
166:                pendingStartTag = nameCode;
167:                elementIsInNullNamespace = null; // meaning not yet computed
168:                currentSimpleType = typeCode;
169:                previousAtomic = false;
170:            }
171:
172:            /**
173:             * Output a namespace declaration. <br>
174:             * This is added to a list of pending namespaces for the current start tag.
175:             * If there is already another declaration of the same prefix, this one is
176:             * ignored, unless the REJECT_DUPLICATES flag is set, in which case this is an error.
177:             * Note that unlike SAX2 startPrefixMapping(), this call is made AFTER writing the start tag.
178:             * @param nscode The namespace code
179:             * @throws XPathException if there is no start tag to write to (created using writeStartTag),
180:             * or if character content has been written since the start tag was written.
181:             */
182:
183:            public void namespace(int nscode, int properties)
184:                    throws XPathException {
185:
186:                // System.err.println("Write namespace prefix=" + (nscode>>16) + " uri=" + (nscode&0xffff));
187:                if (pendingStartTag < 0) {
188:                    throw NoOpenStartTagException.makeNoOpenStartTagException(
189:                            Type.NAMESPACE, getNamePool()
190:                                    .getPrefixFromNamespaceCode(nscode),
191:                            getPipelineConfiguration().getConfiguration()
192:                                    .getHostLanguage(),
193:                            (level <= 0 || pendingStartTag == -2),
194:                            getPipelineConfiguration().isSerializing()
195:                                    && level <= 0);
196:                }
197:
198:                // elimination of namespaces already present on an outer element of the
199:                // result tree is now done by the NamespaceReducer.
200:
201:                // Handle declarations whose prefix is duplicated for this element.
202:
203:                boolean rejectDuplicates = (properties & ReceiverOptions.REJECT_DUPLICATES) != 0;
204:
205:                for (int i = 0; i < pendingNSListSize; i++) {
206:                    if (nscode == pendingNSList[i]) {
207:                        // same prefix and URI: ignore this duplicate
208:                        return;
209:                    }
210:                    if ((nscode >> 16) == (pendingNSList[i] >> 16)) {
211:                        if (rejectDuplicates) {
212:                            DynamicError err = new DynamicError(
213:                                    "Cannot create two namespace nodes with the same name");
214:                            err.setErrorCode("XTDE0430");
215:                            throw err;
216:                        } else {
217:                            // same prefix, do a quick exit
218:                            return;
219:                        }
220:                    }
221:                }
222:
223:                // It is an error to output a namespace node for the default namespace if the element
224:                // itself is in the null namespace, as the resulting element could not be serialized
225:
226:                if (((nscode >> 16) == 0) && ((nscode & 0xffff) != 0)) {
227:                    declaresDefaultNamespace = true;
228:                    if (elementIsInNullNamespace == null) {
229:                        elementIsInNullNamespace = Boolean
230:                                .valueOf(getNamePool().getURI(pendingStartTag) == NamespaceConstant.NULL);
231:                    }
232:                    if (elementIsInNullNamespace.booleanValue()) {
233:                        DynamicError err = new DynamicError(
234:                                "Cannot output a namespace node for the default namespace when the element is in no namespace");
235:                        err.setErrorCode("XTDE0440");
236:                        throw err;
237:                    }
238:                }
239:
240:                // if it's not a duplicate namespace, add it to the list for this start tag
241:
242:                if (pendingNSListSize + 1 > pendingNSList.length) {
243:                    int[] newlist = new int[pendingNSListSize * 2];
244:                    System.arraycopy(pendingNSList, 0, newlist, 0,
245:                            pendingNSListSize);
246:                    pendingNSList = newlist;
247:                }
248:                pendingNSList[pendingNSListSize++] = nscode;
249:                previousAtomic = false;
250:            }
251:
252:            /**
253:             * Output an attribute value. <br>
254:             * This is added to a list of pending attributes for the current start tag, overwriting
255:             * any previous attribute with the same name. <br>
256:             * This method should NOT be used to output namespace declarations.<br>
257:             * @param nameCode The name of the attribute
258:             * @param value The value of the attribute
259:             * @param properties Bit fields containing properties of the attribute to be written
260:             * @throws XPathException if there is no start tag to write to (created using writeStartTag),
261:             * or if character content has been written since the start tag was written.
262:             */
263:
264:            public void attribute(int nameCode, int typeCode,
265:                    CharSequence value, int locationId, int properties)
266:                    throws XPathException {
267:                //System.err.println("Write attribute " + nameCode + "=" + value + " to Outputter " + this);
268:
269:                if (pendingStartTag < 0) {
270:                    // The complexity here is in identifying the right error message and error code
271:                    DynamicError err = NoOpenStartTagException
272:                            .makeNoOpenStartTagException(Type.ATTRIBUTE,
273:                                    getNamePool().getDisplayName(nameCode),
274:                                    getPipelineConfiguration()
275:                                            .getConfiguration()
276:                                            .getHostLanguage(),
277:                                    (level <= 0 || pendingStartTag == -2),
278:                                    getPipelineConfiguration().isSerializing()
279:                                            && level <= 0);
280:                    err.setLocator(new ExpressionLocation(
281:                            getPipelineConfiguration().getLocationProvider(),
282:                            locationId));
283:                    throw err;
284:                }
285:
286:                // if this is a duplicate attribute, overwrite the original, unless
287:                // the REJECT_DUPLICATES option is set.
288:
289:                for (int a = 0; a < pendingAttListSize; a++) {
290:                    if ((pendingAttCode[a] & 0xfffff) == (nameCode & 0xfffff)) {
291:                        if (allowDuplicateAttributes) {
292:                            pendingAttType[a] = typeCode;
293:                            pendingAttValue[a] = value;
294:                            pendingAttLocation[a] = locationId;
295:                            pendingAttProp[a] = properties;
296:                            return;
297:                        } else {
298:                            DynamicError err = new DynamicError(
299:                                    "Cannot create an element having two attributes with the same name: "
300:                                            + Err.wrap(getNamePool()
301:                                                    .getDisplayName(nameCode),
302:                                                    Err.ATTRIBUTE));
303:                            err.setErrorCode("XQDY0025");
304:                            throw err;
305:                        }
306:                    }
307:                }
308:
309:                // otherwise, add this one to the list
310:
311:                if (pendingAttListSize >= pendingAttCode.length) {
312:                    int[] attCode2 = new int[pendingAttListSize * 2];
313:                    int[] attType2 = new int[pendingAttListSize * 2];
314:                    String[] attValue2 = new String[pendingAttListSize * 2];
315:                    int[] attLoc2 = new int[pendingAttListSize * 2];
316:                    int[] attProp2 = new int[pendingAttListSize * 2];
317:                    System.arraycopy(pendingAttCode, 0, attCode2, 0,
318:                            pendingAttListSize);
319:                    System.arraycopy(pendingAttType, 0, attType2, 0,
320:                            pendingAttListSize);
321:                    System.arraycopy(pendingAttValue, 0, attValue2, 0,
322:                            pendingAttListSize);
323:                    System.arraycopy(pendingAttLocation, 0, attLoc2, 0,
324:                            pendingAttListSize);
325:                    System.arraycopy(pendingAttProp, 0, attProp2, 0,
326:                            pendingAttListSize);
327:                    pendingAttCode = attCode2;
328:                    pendingAttType = attType2;
329:                    pendingAttValue = attValue2;
330:                    pendingAttLocation = attLoc2;
331:                    pendingAttProp = attProp2;
332:                }
333:
334:                pendingAttCode[pendingAttListSize] = nameCode;
335:                pendingAttType[pendingAttListSize] = typeCode;
336:                pendingAttValue[pendingAttListSize] = value;
337:                pendingAttLocation[pendingAttListSize] = locationId;
338:                pendingAttProp[pendingAttListSize] = properties;
339:                pendingAttListSize++;
340:                previousAtomic = false;
341:            }
342:
343:            /**
344:             * Check that the prefix for an element or attribute is acceptable, allocating a substitute
345:             * prefix if not. The prefix is acceptable unless a namespace declaration has been
346:             * written that assignes this prefix to a different namespace URI. This method
347:             * also checks that the element or attribute namespace has been declared, and declares it
348:             * if not.
349:             */
350:
351:            private int checkProposedPrefix(int nameCode, int seq)
352:                    throws XPathException {
353:                NamePool namePool = getNamePool();
354:                int nscode = namePool.getNamespaceCode(nameCode);
355:                if (nscode == -1) {
356:                    // avoid calling allocate where possible, because it's synchronized
357:                    nscode = namePool.allocateNamespaceCode(nameCode);
358:                }
359:                int nsprefix = nscode >> 16;
360:
361:                for (int i = 0; i < pendingNSListSize; i++) {
362:                    if (nsprefix == (pendingNSList[i] >> 16)) {
363:                        // same prefix
364:                        if ((nscode & 0xffff) == (pendingNSList[i] & 0xffff)) {
365:                            // same URI
366:                            return nameCode; // all is well
367:                        } else {
368:                            String prefix = getSubstitutePrefix(nscode, seq);
369:
370:                            int newCode = namePool.allocate(prefix, namePool
371:                                    .getURI(nameCode), namePool
372:                                    .getLocalName(nameCode));
373:                            namespace(namePool.allocateNamespaceCode(newCode),
374:                                    0);
375:                            return newCode;
376:                        }
377:                    }
378:                }
379:                // no declaration of this prefix: declare it now
380:                namespace(nscode, 0);
381:                return nameCode;
382:            }
383:
384:            /**
385:             * It is possible for a single output element to use the same prefix to refer to different
386:             * namespaces. In this case we have to generate an alternative prefix for uniqueness. The
387:             * one we generate is based on the sequential position of the element/attribute: this is
388:             * designed to ensure both uniqueness (with a high probability) and repeatability
389:             */
390:
391:            private String getSubstitutePrefix(int nscode, int seq) {
392:                String prefix = getNamePool()
393:                        .getPrefixFromNamespaceCode(nscode);
394:                return prefix + '_' + seq;
395:            }
396:
397:            /**
398:             * Output an element end tag.
399:             */
400:
401:            public void endElement() throws XPathException {
402:                //System.err.println("Write end tag " + this + " : " + name);
403:                if (pendingStartTag >= 0) {
404:                    startContent();
405:                }
406:
407:                // write the end tag
408:
409:                receiver.endElement();
410:                level--;
411:                previousAtomic = false;
412:            }
413:
414:            /**
415:             * Write a comment
416:             */
417:
418:            public void comment(CharSequence comment, int locationId,
419:                    int properties) throws XPathException {
420:                if (pendingStartTag >= 0) {
421:                    startContent();
422:                }
423:                receiver.comment(comment, locationId, properties);
424:                previousAtomic = false;
425:            }
426:
427:            /**
428:             * Write a processing instruction
429:             */
430:
431:            public void processingInstruction(String target, CharSequence data,
432:                    int locationId, int properties) throws XPathException {
433:                if (pendingStartTag >= 0) {
434:                    startContent();
435:                }
436:                receiver.processingInstruction(target, data, locationId,
437:                        properties);
438:                previousAtomic = false;
439:            }
440:
441:            /**
442:             * Append an arbitrary item (node or atomic value) to the output
443:             * @param item the item to be appended
444:             * @param locationId the location of the calling instruction, for diagnostics
445:             * @param copyNamespaces if the item is an element node, this indicates whether its namespaces
446:             */
447:
448:            public void append(Item item, int locationId, int copyNamespaces)
449:                    throws XPathException {
450:                if (item == null) {
451:                    return;
452:                } else if (item instanceof  AtomicValue) {
453:                    if (previousAtomic) {
454:                        characters(" ", locationId, 0);
455:                    }
456:                    characters(item.getStringValueCS(), locationId, 0);
457:                    previousAtomic = true;
458:                } else if (((NodeInfo) item).getNodeKind() == Type.DOCUMENT) {
459:                    SequenceIterator iter = ((NodeInfo) item)
460:                            .iterateAxis(Axis.CHILD);
461:                    while (true) {
462:                        Item it = iter.next();
463:                        if (it == null)
464:                            break;
465:                        append(it, locationId, copyNamespaces);
466:                    }
467:                } else {
468:                    ((NodeInfo) item).copy(this , copyNamespaces, true,
469:                            locationId);
470:                    previousAtomic = false;
471:                }
472:            }
473:
474:            /**
475:             * Close the output
476:             */
477:
478:            public void close() throws XPathException {
479:                // System.err.println("Close " + this + " using emitter " + emitter.getClass());
480:                receiver.close();
481:                previousAtomic = false;
482:            }
483:
484:            /**
485:             * Flush out a pending start tag
486:             */
487:
488:            public void startContent() throws XPathException {
489:
490:                if (pendingStartTag < 0) {
491:                    // this can happen if the method is called from outside,
492:                    // e.g. from a SequenceOutputter earlier in the pipeline
493:                    return;
494:                }
495:
496:                int props = startElementProperties;
497:                int elcode = pendingStartTag;
498:                if (declaresDefaultNamespace || (elcode >> 20 & 0xff) != 0) {
499:                    // skip this check if the element is unprefixed and no xmlns="abc" declaration has been encountered
500:                    elcode = checkProposedPrefix(pendingStartTag, 0);
501:                    props = startElementProperties
502:                            | ReceiverOptions.NAMESPACE_OK;
503:                }
504:                receiver.startElement(elcode, currentSimpleType,
505:                        startElementLocationId, props);
506:
507:                for (int a = 0; a < pendingAttListSize; a++) {
508:                    int attcode = pendingAttCode[a];
509:                    if ((attcode >> 20 & 0xff) != 0) { // non-null prefix
510:                        pendingAttCode[a] = checkProposedPrefix(attcode, a + 1);
511:                    }
512:                }
513:
514:                for (int n = 0; n < pendingNSListSize; n++) {
515:                    receiver.namespace(pendingNSList[n], 0);
516:                }
517:
518:                for (int a = 0; a < pendingAttListSize; a++) {
519:                    receiver.attribute(pendingAttCode[a], pendingAttType[a],
520:                            pendingAttValue[a], pendingAttLocation[a],
521:                            pendingAttProp[a]);
522:                }
523:
524:                receiver.startContent();
525:
526:                pendingAttListSize = 0;
527:                pendingNSListSize = 0;
528:                pendingStartTag = -1;
529:                previousAtomic = false;
530:            }
531:
532:        }
533:
534:        //
535:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
536:        // you may not use this file except in compliance with the License. You may obtain a copy of the
537:        // License at http://www.mozilla.org/MPL/
538:        //
539:        // Software distributed under the License is distributed on an "AS IS" basis,
540:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
541:        // See the License for the specific language governing rights and limitations under the License.
542:        //
543:        // The Original Code is: all this file.
544:        //
545:        // The Initial Developer of the Original Code is Michael H. Kay.
546:        //
547:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
548:        //
549:        // Contributor(s): none.
550:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.