001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.om.NameChecker;
005: import net.sf.saxon.trans.DynamicError;
006:
007: import javax.xml.transform.OutputKeys;
008: import java.util.StringTokenizer;
009:
010: /**
011: * Provides string constants that can be used to set
012: * output properties for a Transformer, or to retrieve
013: * output properties from a Transformer or Templates object.
014: *
015: * These keys are private Saxon keys that supplement the standard keys
016: * defined in javax.xml.transform.OutputKeys. As well as Saxon extension
017: * attributes, the list includes new attributes defined in XSLT 2.0 which
018: * are not yet supported in JAXP
019: */
020:
021: public class SaxonOutputKeys {
022:
023: /**
024: * This class is not instantiated
025: */
026:
027: private SaxonOutputKeys() {
028: }
029:
030: /**
031: * indentSpaces = integer.
032: *
033: * <p>Defines the number of spaces used for indentation of output</p>
034: */
035:
036: public static final String INDENT_SPACES = "{http://saxon.sf.net/}indent-spaces";
037:
038: /**
039: * stylesheet-version. This serialization parameter is set automatically by the XSLT processor
040: * to the value of the version attribute on the principal stylesheet module.
041: */
042:
043: public static final String STYLESHEET_VERSION = "{http://saxon.sf.net/}stylesheet-version";
044:
045: /**
046: * use-character-map = list-of-qnames.
047: *
048: * <p>Defines the character maps used in this output definition. The QNames
049: * are represented in Clark notation as {uri}local-name.</p>
050: */
051:
052: public static final String USE_CHARACTER_MAPS = "use-character-maps";
053:
054: /**
055: * include-content-type = "yes" | "no". This attribute is defined in XSLT 2.0
056: *
057: * <p>Indicates whether the META tag is to be added to HTML output</p>
058: */
059:
060: public static final String INCLUDE_CONTENT_TYPE = "include-content-type";
061:
062: /**
063: * undeclare-prefixes = "yes" | "no". This attribute is defined in XSLT 2.0
064: *
065: * <p>Indicates XML 1.1 namespace undeclarations are to be output when required</p>
066: */
067:
068: public static final String UNDECLARE_PREFIXES = "undeclare-prefixes";
069:
070: /**
071: * escape-uri-attributes = "yes" | "no". This attribute is defined in XSLT 2.0
072: *
073: * <p>Indicates whether HTML attributes of type URI are to be URI-escaped</p>
074: */
075:
076: public static final String ESCAPE_URI_ATTRIBUTES = "escape-uri-attibutes";
077:
078: /**
079: * representation = rep1[;rep2].
080: *
081: * <p>Indicates the preferred way of representing non-ASCII characters in HTML
082: * and XML output. rep1 is for characters in the range 128-256, rep2 for those
083: * above 256.</p>
084: */
085: public static final String CHARACTER_REPRESENTATION = "{http://saxon.sf.net/}character-representation";
086:
087: /**
088: * saxon:next-in-chain = URI.
089: *
090: * <p>Indicates that the output is to be piped into another XSLT stylesheet
091: * to perform another transformation. The auxiliary property NEXT_IN_CHAIN_BASE_URI
092: * records the base URI of the stylesheet element where this attribute was found.</p>
093: */
094: public static final String NEXT_IN_CHAIN = "{http://saxon.sf.net/}next-in-chain";
095: public static final String NEXT_IN_CHAIN_BASE_URI = "{http://saxon.sf.net/}next-in-chain-base-uri";
096:
097: /**
098: * byte-order-mark = yes|no.
099: *
100: * <p>Indicates whether UTF-8/UTF-16 output is to start with a byte order mark. Values are "yes" or "no",
101: * default is "no"
102: */
103:
104: public static final String BYTE_ORDER_MARK = "byte-order-mark";
105:
106: /**
107: * normalization-form = NFC|NFD|NFKC|NFKD|non.
108: *
109: * <p>Indicates that a given Unicode normalization form (or no normalization) is required.
110: */
111:
112: public static final String NORMALIZATION_FORM = "normalization-form";
113:
114: /**
115: * saxon:require-well-formed = yes|no.
116: *
117: * <p>Indicates whether a user-supplied ContentHandler requires the stream of SAX events to be
118: * well-formed (that is, to have a single element node and no text nodes as children of the root).
119: * The default is "no".</p>
120: */
121:
122: public static final String REQUIRE_WELL_FORMED = "{http://saxon.sf.net/}require-well-formed";
123:
124: /**
125: * wrap="yes"|"no".
126: * <p>
127: * This property is only available in the XQuery API. The value "yes" indicates that the result
128: * sequence produced by the query is to be wrapped, that is, each item in the result is represented
129: * as a separate element. This format allows any sequence to be represented as an XML document,
130: * including for example sequences consisting of parentless attribute nodes.
131: */
132:
133: public static final String WRAP = "{http://saxon.sf.net/}wrap-result-sequence";
134:
135: /**
136: * Check that a supplied output property is valid.
137: * @param key the name of the property
138: * @param value the value of the property. This may be set to null, in which case
139: * @param checker
140: */
141:
142: public static final void checkOutputProperty(String key,
143: String value, NameChecker checker) throws DynamicError {
144: if (!key.startsWith("{")
145: || key.startsWith("{http://saxon.sf.net/}")) {
146: if (key.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
147: if (value != null) {
148: checkListOfClarkNames(key, value, checker);
149: }
150: } else if (key.equals(OutputKeys.DOCTYPE_PUBLIC)) {
151: // no constraints
152: } else if (key.equals(OutputKeys.DOCTYPE_SYSTEM)) {
153: // no constraints
154: } else if (key.equals(OutputKeys.ENCODING)) {
155: // no constraints
156: } else if (key.equals(OutputKeys.INDENT)) {
157: if (value != null) {
158: checkYesOrNo(key, value);
159: }
160: } else if (key.equals(OutputKeys.MEDIA_TYPE)) {
161: // no constraints
162: } else if (key.equals(OutputKeys.METHOD)) {
163: if (value != null) {
164: checkMethod(value, checker);
165: }
166: } else if (key.equals(OutputKeys.OMIT_XML_DECLARATION)) {
167: if (value != null) {
168: checkYesOrNo(key, value);
169: }
170: } else if (key.equals(OutputKeys.STANDALONE)) {
171: if (value != null && !value.equals("omit")) {
172: checkYesOrNo(key, value);
173: }
174: } else if (key.equals(OutputKeys.VERSION)) {
175: // no constraints
176: } else if (key.equals(STYLESHEET_VERSION)) {
177: // no constraints
178: } else if (key.equals(INDENT_SPACES)) {
179: if (value != null) {
180: checkNonNegativeInteger(key, value);
181: }
182: } else if (key.equals(INCLUDE_CONTENT_TYPE)) {
183: if (value != null) {
184: checkYesOrNo(key, value);
185: }
186: } else if (key.equals(ESCAPE_URI_ATTRIBUTES)) {
187: if (value != null) {
188: checkYesOrNo(key, value);
189: }
190: } else if (key.equals(CHARACTER_REPRESENTATION)) {
191: // no validation performed
192: } else if (key.equals(NEXT_IN_CHAIN)) {
193: // no validation performed
194: } else if (key.equals(NEXT_IN_CHAIN_BASE_URI)) {
195: // no validation performed
196: } else if (key.equals(UNDECLARE_PREFIXES)) {
197: if (value != null) {
198: checkYesOrNo(key, value);
199: }
200: } else if (key.equals(USE_CHARACTER_MAPS)) {
201: if (value != null) {
202: checkListOfClarkNames(key, value, checker);
203: }
204: } else if (key.equals(REQUIRE_WELL_FORMED)) {
205: if (value != null) {
206: checkYesOrNo(key, value);
207: }
208: } else if (key.equals(BYTE_ORDER_MARK)) {
209: if (value != null) {
210: checkYesOrNo(key, value);
211: }
212: } else if (key.equals(WRAP)) {
213: if (value != null) {
214: checkYesOrNo(key, value);
215: }
216: } else {
217: throw new DynamicError(
218: "Unknown serialization parameter "
219: + Err.wrap(key));
220: }
221: } else {
222: return;
223: }
224: }
225:
226: private static void checkYesOrNo(String key, String value)
227: throws DynamicError {
228: if ("yes".equals(value) || "no".equals(value)) {
229: // OK
230: } else {
231: throw new DynamicError("Serialization parameter "
232: + Err.wrap(key) + " must have the value yes or no");
233: }
234: }
235:
236: private static void checkMethod(String value, NameChecker checker)
237: throws DynamicError {
238: if ("xml".equals(value))
239: return;
240: if ("html".equals(value))
241: return;
242: if ("xhtml".equals(value))
243: return;
244: if ("text".equals(value))
245: return;
246: if (isValidClarkName(value, checker))
247: return;
248: throw new DynamicError(
249: "Invalid value for serialization method: "
250: + "must be xml, html, xhtml, text, or a QName in '{uri}local' form");
251:
252: }
253:
254: private static boolean isValidClarkName(String value,
255: NameChecker checker) {
256: if (value.charAt(0) != '{')
257: return false;
258: int closer = value.indexOf('}');
259: if (closer < 2)
260: return false;
261: if (closer == value.length() - 1)
262: return false;
263: if (!checker.isValidNCName(value.substring(closer + 1)))
264: return false;
265: return true;
266: }
267:
268: private static void checkNonNegativeInteger(String key, String value)
269: throws DynamicError {
270: try {
271: int n = Integer.parseInt(value);
272: if (n < 0) {
273: throw new DynamicError("Value of " + Err.wrap(key)
274: + " must be a non-negative integer");
275: }
276: } catch (NumberFormatException err) {
277: throw new DynamicError("Value of " + Err.wrap(key)
278: + " must be a non-negative integer");
279: }
280: }
281:
282: private static void checkListOfClarkNames(String key, String value,
283: NameChecker checker) throws DynamicError {
284: StringTokenizer tok = new StringTokenizer(value);
285: while (tok.hasMoreTokens()) {
286: String s = tok.nextToken();
287: if (isValidClarkName(s, checker)
288: || checker.isValidNCName(s)) {
289: // ok
290: } else {
291: throw new DynamicError(
292: "Value of "
293: + Err.wrap(key)
294: + " must be a list of QNames in '{uri}local' notation");
295: }
296: }
297: }
298:
299: }
300:
301: //
302: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
303: // you may not use this file except in compliance with the License. You may obtain a copy of the
304: // License at http://www.mozilla.org/MPL/
305: //
306: // Software distributed under the License is distributed on an "AS IS" basis,
307: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
308: // See the License for the specific language governing rights and limitations under the License.
309: //
310: // The Original Code is: all this file.
311: //
312: // The Initial Developer of the Original Code is Michael H. Kay.
313: //
314: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
315: //
316: // Contributor(s): none.
317: //
|