1 package net.sf.saxon.style; 2 import net.sf.saxon.event.SaxonOutputKeys; 3 import net.sf.saxon.expr.Expression; 4 import net.sf.saxon.instruct.Executable; 5 import net.sf.saxon.om.*; 6 import net.sf.saxon.trans.SaxonErrorCode; 7 import net.sf.saxon.trans.XPathException; 8 9 import javax.xml.transform.OutputKeys ; 10 import java.util.HashMap ; 11 import java.util.Iterator ; 12 import java.util.Properties ; 13 import java.util.StringTokenizer ; 14 15 18 19 public class XSLOutput extends StyleElement { 20 21 private int fingerprint = -1; 22 private String method = null; 23 private String version = null; 24 private String indent = null; 25 private String encoding = null; 26 private String mediaType = null; 27 private String doctypeSystem = null; 28 private String doctypePublic = null; 29 private String omitDeclaration = null; 30 private String standalone = null; 31 private String cdataElements = null; 32 private String includeContentType = null; 33 private String nextInChain = null; 34 private String representation = null; 35 private String indentSpaces = null; 36 private String byteOrderMark = null; 37 private String escapeURIAttributes = null; 38 private String normalizationForm = null; 39 private String requireWellFormed = null; 40 private String undeclareNamespaces = null; 41 private String useCharacterMaps = null; 42 private HashMap userAttributes = null; 43 44 46 public void prepareAttributes() throws XPathException { 47 AttributeCollection atts = getAttributeList(); 48 String nameAtt = null; 49 50 for (int a=0; a<atts.getLength(); a++) { 51 int nc = atts.getNameCode(a); 52 String f = getNamePool().getClarkName(nc); 53 if (f==StandardNames.NAME) { 54 nameAtt = atts.getValue(a).trim(); 55 } else if (f==StandardNames.METHOD) { 56 method = atts.getValue(a).trim(); 57 } else if (f==StandardNames.VERSION) { 58 version = atts.getValue(a).trim(); 59 } else if (f==StandardNames.BYTE_ORDER_MARK) { 60 byteOrderMark = atts.getValue(a).trim(); 61 } else if (f==StandardNames.ENCODING) { 62 encoding = atts.getValue(a).trim(); 63 } else if (f==StandardNames.OMIT_XML_DECLARATION) { 64 omitDeclaration = atts.getValue(a).trim(); 65 } else if (f==StandardNames.STANDALONE) { 66 standalone = atts.getValue(a).trim(); 67 } else if (f==StandardNames.DOCTYPE_PUBLIC) { 68 doctypePublic = atts.getValue(a).trim(); 69 } else if (f==StandardNames.DOCTYPE_SYSTEM) { 70 doctypeSystem = atts.getValue(a).trim(); 71 } else if (f==StandardNames.CDATA_SECTION_ELEMENTS) { 72 cdataElements = atts.getValue(a); 73 } else if (f==StandardNames.INDENT) { 74 indent = atts.getValue(a).trim(); 75 } else if (f==StandardNames.MEDIA_TYPE) { 76 mediaType = atts.getValue(a).trim(); 77 } else if (f==StandardNames.INCLUDE_CONTENT_TYPE) { 78 includeContentType = atts.getValue(a).trim(); 79 } else if (f==StandardNames.NORMALIZATION_FORM) { 80 normalizationForm = atts.getValue(a).trim(); 81 } else if (f==StandardNames.ESCAPE_URI_ATTRIBUTES) { 82 escapeURIAttributes = atts.getValue(a).trim(); 83 } else if (f==StandardNames.USE_CHARACTER_MAPS) { 84 useCharacterMaps = atts.getValue(a); 85 } else if (f==StandardNames.UNDECLARE_PREFIXES) { 86 undeclareNamespaces = atts.getValue(a); 87 } else if (f==StandardNames.SAXON_CHARACTER_REPRESENTATION) { 88 representation = atts.getValue(a).trim(); 89 } else if (f==StandardNames.SAXON_INDENT_SPACES) { 90 indentSpaces = atts.getValue(a).trim(); 91 } else if (f==StandardNames.SAXON_NEXT_IN_CHAIN) { 92 nextInChain = atts.getValue(a).trim(); 93 } else if (f==StandardNames.SAXON_REQUIRE_WELL_FORMED) { 94 requireWellFormed = atts.getValue(a).trim(); 95 } else { 96 String attributeURI = getNamePool().getURI(nc); 97 if ("".equals(attributeURI) || 98 NamespaceConstant.XSLT.equals(attributeURI) || 99 NamespaceConstant.SAXON.equals(attributeURI)) { 100 checkUnknownAttribute(nc); 101 } else { 102 String name = '{' + attributeURI + '}' + atts.getLocalName(a); 103 if (userAttributes==null) { 104 userAttributes = new HashMap (5); 105 } 106 userAttributes.put(name, atts.getValue(a)); 107 } 108 } 109 } 110 if (nameAtt!=null) { 111 try { 112 fingerprint = makeNameCode(nameAtt.trim()) & 0xfffff; 113 } catch (NamespaceException err) { 114 compileError(err.getMessage(), "XTSE1570"); 115 } catch (XPathException err) { 116 compileError(err.getMessage(), "XTSE1570"); 117 } 118 } 119 } 120 121 125 126 public int getOutputFingerprint() { 127 return fingerprint; 128 } 129 130 public void validate() throws XPathException { 131 checkTopLevel(null); 132 checkEmpty(); 133 } 134 135 public Expression compile(Executable exec) { 136 return null; 137 } 138 139 140 144 145 protected void gatherOutputProperties(Properties details, HashMap precedences) 146 throws XPathException { 147 148 if (method != null) { 149 if (method.equals("xml") || method.equals("html") || 150 method.equals("text") || method.equals("xhtml")) { 151 checkAndPut(OutputKeys.METHOD, method, details, precedences); 152 } else { 154 String [] parts; 155 try { 156 parts = Name.getQNameParts(method); 157 String prefix = parts[0]; 158 if (prefix.equals("")) { 159 compileError("method must be xml, html, xhtml, or text, or a prefixed name", "XTSE1570"); 160 } else { 161 String uri = getURIForPrefix(prefix, false); 162 if (uri == null) { 163 undeclaredNamespaceError(prefix, "XTSE0280"); 164 } 165 checkAndPut(OutputKeys.METHOD, '{' + uri + '}' + parts[1], details, precedences); 166 } 168 } catch (QNameException e) { 169 compileError("Invalid method name. " + e.getMessage(), "XTSE1570"); 170 } 171 } 172 } 173 174 if (byteOrderMark != null) { 175 if (byteOrderMark.equals("yes") || byteOrderMark.equals("no")) { 176 checkAndPut(SaxonOutputKeys.BYTE_ORDER_MARK, byteOrderMark, details, precedences); 177 } else { 179 compileError("byte-order-mark value must be 'yes' or 'no'", "XTSE0020"); 180 } 181 } 182 183 if (version != null) { 184 checkAndPut(OutputKeys.VERSION, version, details, precedences); 185 } 187 188 if (indent != null) { 189 if (indent.equals("yes") || indent.equals("no")) { 190 checkAndPut(OutputKeys.INDENT, indent, details, precedences); 192 } else { 193 compileError("indent value must be 'yes' or 'no'", "XTSE0020"); 194 } 195 } 196 197 if (indentSpaces != null) { 198 try { 199 Integer.parseInt(indentSpaces); 200 details.put(OutputKeys.INDENT, "yes"); 201 checkAndPut(SaxonOutputKeys.INDENT_SPACES, indentSpaces, details, precedences); 202 } catch (NumberFormatException err) { 204 compileWarning("saxon:indent-spaces must be an integer. Using default value (3).", 205 SaxonErrorCode.SXWN9002); 206 } 207 } 208 209 if (encoding != null) { 210 checkAndPut(OutputKeys.ENCODING, encoding, details, precedences); 211 } 213 214 if (mediaType != null) { 215 checkAndPut(OutputKeys.MEDIA_TYPE, mediaType, details, precedences); 216 } 218 219 if (doctypeSystem != null) { 220 checkAndPut(OutputKeys.DOCTYPE_SYSTEM, doctypeSystem, details, precedences); 221 } 223 224 if (doctypePublic != null) { 225 checkAndPut(OutputKeys.DOCTYPE_PUBLIC, doctypePublic, details, precedences); 226 } 228 229 if (omitDeclaration != null) { 230 if (omitDeclaration.equals("yes") || omitDeclaration.equals("no")) { 231 checkAndPut(OutputKeys.OMIT_XML_DECLARATION, omitDeclaration, details, precedences); 232 } else { 234 compileError("omit-xml-declaration attribute must be 'yes' or 'no'", "XTSE0020"); 235 } 236 } 237 238 if (standalone != null) { 239 if (standalone.equals("yes") || standalone.equals("no") || standalone.equals("omit")) { 240 checkAndPut(OutputKeys.STANDALONE, standalone, details, precedences); 241 } else { 243 compileError("standalone attribute must be 'yes' or 'no' or 'omit'", "XTSE0020"); 244 } 245 } 246 247 if (cdataElements != null) { 248 String existing = details.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); 249 if (existing==null) { 250 existing = ""; 251 } 252 String s = ""; 253 StringTokenizer st = new StringTokenizer (cdataElements); 254 while (st.hasMoreTokens()) { 255 String displayname = st.nextToken(); 256 try { 257 String [] parts = Name.getQNameParts(displayname); 258 String uri = getURIForPrefix(parts[0], true); 259 if (uri == null) { 260 undeclaredNamespaceError(parts[0], "XTSE0280"); 261 } 262 s += " {" + uri + '}' + parts[1]; 263 } catch (QNameException err) { 264 compileError("Invalid CDATA element name. " + err.getMessage(), "XTSE0280"); 265 } 266 267 details.put(OutputKeys.CDATA_SECTION_ELEMENTS, existing+s); 268 } 269 } 270 271 if (normalizationForm != null && !normalizationForm.equals("none")) { 272 if (normalizationForm.equals("NFC") || normalizationForm.equals("NFD") || 273 normalizationForm.equals("NFKC") || normalizationForm.equals("NFKD") ) { 274 checkAndPut(SaxonOutputKeys.NORMALIZATION_FORM, normalizationForm, details, precedences); 275 } else { 276 compileError("normalization-form must be one of NFC, NFD, NFKC, NFKD, or 'none'", "XTSE0020"); 277 } 278 } 279 280 if (undeclareNamespaces != null) { 281 if (undeclareNamespaces.equals("yes") || undeclareNamespaces.equals("no")) { 282 checkAndPut(SaxonOutputKeys.UNDECLARE_PREFIXES, undeclareNamespaces, details, precedences); 283 } else { 285 compileError("undeclare-namespaces value must be 'yes' or 'no'", "XTSE0020"); 286 } 287 } 288 289 if (useCharacterMaps != null) { 290 String s = prepareCharacterMaps(this, useCharacterMaps, details); 291 details.put(SaxonOutputKeys.USE_CHARACTER_MAPS, s); 292 } 293 294 if (representation != null) { 295 checkAndPut(SaxonOutputKeys.CHARACTER_REPRESENTATION, representation, details, precedences); 296 } 298 299 if (includeContentType != null) { 300 if (includeContentType.equals("yes") || includeContentType.equals("no")) { 301 checkAndPut(SaxonOutputKeys.INCLUDE_CONTENT_TYPE, includeContentType, details, precedences); 302 } else { 304 compileError("include-content-type attribute must be 'yes' or 'no'", "XTSE0020"); 305 } 306 } 307 308 if (escapeURIAttributes != null) { 309 if (escapeURIAttributes.equals("yes") || escapeURIAttributes.equals("no")) { 310 checkAndPut(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES, escapeURIAttributes, details, precedences); 311 } else { 313 compileError("escape-uri-attributes value must be 'yes' or 'no'", "XTSE0020"); 314 } 315 } 316 317 if (nextInChain != null) { 318 checkAndPut(SaxonOutputKeys.NEXT_IN_CHAIN, nextInChain, details, precedences); 319 checkAndPut(SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI, getSystemId(), details, precedences); 320 } 323 324 if (requireWellFormed != null) { 325 if (requireWellFormed.equals("yes") || requireWellFormed.equals("no")) { 326 checkAndPut(SaxonOutputKeys.REQUIRE_WELL_FORMED, requireWellFormed, details, precedences); 327 } else { 329 compileWarning("saxon:require-well-formed value must be 'yes' or 'no' (treated as no)", 330 SaxonErrorCode.SXWN9003); 331 } 332 } 333 334 336 if (userAttributes!=null) { 337 Iterator iter = userAttributes.keySet().iterator(); 338 while (iter.hasNext()) { 339 String attName = (String )iter.next(); 340 String data = (String )userAttributes.get(attName); 341 details.put(attName, data); 342 } 343 } 344 345 } 346 347 351 352 public void checkAndPut(String property, String value, Properties props, HashMap precedences) 353 throws XPathException { 354 String old = props.getProperty(property); 355 if (old == null) { 356 props.setProperty(property, value); 357 precedences.put(property, new Integer (getPrecedence())); 358 } else if (old.equals(value)) { 359 } else { 361 Integer oldPrec = (Integer )precedences.get(property); 362 if (oldPrec == null) return; int op = oldPrec.intValue(); 364 if (op > getPrecedence()) { 365 } else if (op == getPrecedence()) { 367 compileError("Conflicting values for output property " + property, "XTSE1560"); 368 } else { 369 throw new IllegalStateException ("Output properties must be processed in decreasing precedence order"); 371 } 372 } 373 } 374 375 380 public static String prepareCharacterMaps(StyleElement element, 381 String useCharacterMaps, 382 Properties details) 383 throws XPathException { 384 XSLStylesheet principal = element.getPrincipalStylesheet(); 385 String existing = details.getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS); 386 if (existing==null) { 387 existing = ""; 388 } 389 String s = ""; 390 StringTokenizer st = new StringTokenizer (useCharacterMaps); 391 while (st.hasMoreTokens()) { 392 String displayname = st.nextToken(); 393 try { 394 String [] parts = Name.getQNameParts(displayname); 395 String uri = element.getURIForPrefix(parts[0], false); 396 if (uri == null) { 397 element.undeclaredNamespaceError(parts[0], "XT0280"); 398 } 399 int nameCode = element.getTargetNamePool().allocate(parts[0], uri, parts[1]); 400 XSLCharacterMap ref = 401 principal.getCharacterMap(nameCode & 0xfffff); 402 if (ref == null) { 403 element.compileError("No character-map named '" + displayname + "' has been defined", "XTSE1590"); 404 } 405 s += " {" + uri + '}' + parts[1]; 406 } catch (QNameException err) { 407 element.compileError("Invalid character-map name. " + err.getMessage(), "XTSE1590"); 408 } 409 410 } 411 existing = s + existing; 412 return existing; 413 } 414 415 } 416 417 | Popular Tags |