001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.trans.XPathException;
004: import net.sf.saxon.trans.DynamicError;
005: import net.sf.saxon.om.NameChecker;
006: import net.sf.saxon.om.Name10Checker;
007: import net.sf.saxon.om.NamePool;
008: import net.sf.saxon.om.XMLChar;
009: import net.sf.saxon.Err;
010: import net.sf.saxon.expr.ExpressionLocation;
011: import net.sf.saxon.sort.IntHashSet;
012:
013: /**
014: * This class is used on the serialization pipeline to check that the document conforms
015: * to XML 1.0 rules. It is placed on the pipeline only when the configuration permits
016: * XML 1.1 constructs, but the particular output document is being serialized as XML 1.0
017: */
018:
019: public class XML10ContentChecker extends ProxyReceiver {
020:
021: private NameChecker checker = Name10Checker.getInstance();
022: private NamePool pool;
023: private IntHashSet cache = new IntHashSet(100);
024:
025: public void setPipelineConfiguration(PipelineConfiguration pipe) {
026: pool = pipe.getConfiguration().getNamePool();
027: super .setPipelineConfiguration(pipe);
028: }
029:
030: /**
031: * Notify the start of an element
032: *
033: * @param nameCode integer code identifying the name of the element within the name pool.
034: * @param typeCode integer code identifying the element's type within the name pool.
035: * @param properties properties of the element node
036: */
037:
038: public void startElement(int nameCode, int typeCode,
039: int locationId, int properties) throws XPathException {
040: if (!cache.contains(nameCode)) {
041: if (!checker.isValidNCName(pool.getLocalName(nameCode))) {
042: DynamicError err = new DynamicError(
043: "Invalid XML 1.0 element name "
044: + Err.wrap(pool.getLocalName(nameCode),
045: Err.ELEMENT));
046: err.setErrorCode("SERE0005");
047: err.setLocator(new ExpressionLocation(
048: getPipelineConfiguration()
049: .getLocationProvider(), locationId));
050: throw err;
051: }
052: cache.add(nameCode);
053: }
054: nextReceiver.startElement(nameCode, typeCode, locationId,
055: properties);
056: }
057:
058: /**
059: * Notify an attribute. Attributes are notified after the startElement event, and before any
060: * children. Namespaces and attributes may be intermingled.
061: *
062: * @param nameCode The name of the attribute, as held in the name pool
063: * @param typeCode The type of the attribute, as held in the name pool
064: * @param properties Bit significant value. The following bits are defined:
065: * <dd>DISABLE_ESCAPING</dd> <dt>Disable escaping for this attribute</dt>
066: * <dd>NO_SPECIAL_CHARACTERS</dd> <dt>Attribute value contains no special characters</dt>
067: * @throws IllegalStateException: attempt to output an attribute when there is no open element
068: * start tag
069: */
070:
071: public void attribute(int nameCode, int typeCode,
072: CharSequence value, int locationId, int properties)
073: throws XPathException {
074: if (!cache.contains(nameCode)) {
075: if (!checker.isValidNCName(pool.getLocalName(nameCode))) {
076: DynamicError err = new DynamicError(
077: "Invalid XML 1.0 attribute name "
078: + Err.wrap(pool.getLocalName(nameCode),
079: Err.ATTRIBUTE));
080: err.setErrorCode("SERE0005");
081: err.setLocator(new ExpressionLocation(
082: getPipelineConfiguration()
083: .getLocationProvider(), locationId));
084: throw err;
085: }
086: cache.add(nameCode);
087: }
088: checkString(value, locationId);
089: nextReceiver.attribute(nameCode, typeCode, value, locationId,
090: properties);
091: }
092:
093: /**
094: * Character data
095: */
096:
097: public void characters(CharSequence chars, int locationId,
098: int properties) throws XPathException {
099: checkString(chars, locationId);
100: nextReceiver.characters(chars, locationId, properties);
101: }
102:
103: /**
104: * Output a comment
105: */
106:
107: public void comment(CharSequence chars, int locationId,
108: int properties) throws XPathException {
109: checkString(chars, locationId);
110: nextReceiver.comment(chars, locationId, properties);
111: }
112:
113: /**
114: * Processing Instruction
115: */
116:
117: public void processingInstruction(String target, CharSequence data,
118: int locationId, int properties) throws XPathException {
119: if (!checker.isValidNCName(target)) {
120: DynamicError err = new DynamicError(
121: "Invalid XML 1.0 processing instruction name "
122: + Err.wrap(target));
123: err.setErrorCode("SERE0005");
124: err.setLocator(new ExpressionLocation(
125: getPipelineConfiguration().getLocationProvider(),
126: locationId));
127: throw err;
128: }
129: checkString(data, locationId);
130: nextReceiver.processingInstruction(target, data, locationId,
131: properties);
132: }
133:
134: /**
135: * Check that a string consists of valid XML 1.0 characters (UTF-16 encoded)
136: */
137:
138: private void checkString(CharSequence in, int locationId)
139: throws XPathException {
140: final int len = in.length();
141: for (int c = 0; c < len; c++) {
142: int ch32 = in.charAt(c);
143: if (XMLChar.isHighSurrogate(ch32)) {
144: char low = in.charAt(c++);
145: ch32 = XMLChar.supplemental((char) ch32, low);
146: }
147: if (!XMLChar.isValid(ch32)) {
148: DynamicError err = new DynamicError(
149: "The result tree contains a character not allowed by XML 1.0 (hex "
150: + Integer.toHexString(ch32) + ')');
151: err.setErrorCode("XTDE1180");
152: err.setLocator(new ExpressionLocation(
153: getPipelineConfiguration()
154: .getLocationProvider(), locationId));
155: throw err;
156: }
157: }
158: }
159:
160: }
161:
162: //
163: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
164: // you may not use this file except in compliance with the License. You may obtain a copy of the
165: // License at http://www.mozilla.org/MPL/
166: //
167: // Software distributed under the License is distributed on an "AS IS" basis,
168: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
169: // See the License for the specific language governing rights and limitations under the License.
170: //
171: // The Original Code is: all this file.
172: //
173: // The Initial Developer of the Original Code is Michael H. Kay. The detectEncoding() method includes
174: // code fragments taken from the AElfred XML Parser developed by David Megginson.
175: //
176: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
177: //
178: // Contributor(s): none.
179: //
|