1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.serialize;
  58. import java.util.Stack;
  59. import java.io.Writer;
  60. import java.io.IOException;
  61. import java.util.Hashtable;
  62. import java.util.Vector;
  63. import java.util.Properties;
  64. import java.util.BitSet;
  65. import org.xml.sax.*;
  66. import org.apache.xml.utils.BoolStack;
  67. import org.apache.xml.utils.Trie;
  68. import org.apache.xml.utils.FastStringBuffer;
  69. import org.apache.xalan.res.XSLMessages;
  70. import org.apache.xpath.res.XPATHErrorResources;
  71. import org.apache.xml.utils.StringToIntTable;
  72. import org.apache.xalan.templates.OutputProperties;
  73. import javax.xml.transform.OutputKeys;
  74. import javax.xml.transform.Result;
  75. /**
  76. * <meta name="usage" content="general"/>
  77. * SerializerToHTML formats SAX-style events into XML.
  78. */
  79. public class SerializerToHTML extends SerializerToXML
  80. {
  81. /** State stack to keep track of if the current element has output
  82. * escaping disabled. */
  83. protected BoolStack m_isRawStack = new BoolStack();
  84. /** True if the current element is a block element. (seems like
  85. * this needs to be a stack. -sb). */
  86. private boolean m_inBlockElem = false;
  87. /**
  88. * Map that tells which XML characters should have special treatment, and it
  89. * provides character to entity name lookup.
  90. */
  91. protected static CharInfo m_htmlcharInfo =
  92. new CharInfo(CharInfo.HTML_ENTITIES_RESOURCE);
  93. /** A digital search trie for fast, case insensitive lookup of ElemDesc objects. */
  94. static Trie m_elementFlags = new Trie();
  95. static
  96. {
  97. // HTML 4.0 loose DTD
  98. m_elementFlags.put("BASEFONT", new ElemDesc(0 | ElemDesc.EMPTY));
  99. m_elementFlags.put("FRAME",
  100. new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
  101. m_elementFlags.put("FRAMESET", new ElemDesc(0 | ElemDesc.BLOCK));
  102. m_elementFlags.put("NOFRAMES", new ElemDesc(0 | ElemDesc.BLOCK));
  103. m_elementFlags.put("ISINDEX",
  104. new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
  105. m_elementFlags.put("APPLET",
  106. new ElemDesc(0 | ElemDesc.WHITESPACESENSITIVE));
  107. m_elementFlags.put("CENTER", new ElemDesc(0 | ElemDesc.BLOCK));
  108. m_elementFlags.put("DIR", new ElemDesc(0 | ElemDesc.BLOCK));
  109. m_elementFlags.put("MENU", new ElemDesc(0 | ElemDesc.BLOCK));
  110. // HTML 4.0 strict DTD
  111. m_elementFlags.put("TT", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  112. m_elementFlags.put("I", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  113. m_elementFlags.put("B", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  114. m_elementFlags.put("BIG", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  115. m_elementFlags.put("SMALL", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  116. m_elementFlags.put("EM", new ElemDesc(0 | ElemDesc.PHRASE));
  117. m_elementFlags.put("STRONG", new ElemDesc(0 | ElemDesc.PHRASE));
  118. m_elementFlags.put("DFN", new ElemDesc(0 | ElemDesc.PHRASE));
  119. m_elementFlags.put("CODE", new ElemDesc(0 | ElemDesc.PHRASE));
  120. m_elementFlags.put("SAMP", new ElemDesc(0 | ElemDesc.PHRASE));
  121. m_elementFlags.put("KBD", new ElemDesc(0 | ElemDesc.PHRASE));
  122. m_elementFlags.put("VAR", new ElemDesc(0 | ElemDesc.PHRASE));
  123. m_elementFlags.put("CITE", new ElemDesc(0 | ElemDesc.PHRASE));
  124. m_elementFlags.put("ABBR", new ElemDesc(0 | ElemDesc.PHRASE));
  125. m_elementFlags.put("ACRONYM", new ElemDesc(0 | ElemDesc.PHRASE));
  126. m_elementFlags.put("SUP",
  127. new ElemDesc(0 | ElemDesc.SPECIAL
  128. | ElemDesc.ASPECIAL));
  129. m_elementFlags.put("SUB",
  130. new ElemDesc(0 | ElemDesc.SPECIAL
  131. | ElemDesc.ASPECIAL));
  132. m_elementFlags.put("SPAN",
  133. new ElemDesc(0 | ElemDesc.SPECIAL
  134. | ElemDesc.ASPECIAL));
  135. m_elementFlags.put("BDO",
  136. new ElemDesc(0 | ElemDesc.SPECIAL
  137. | ElemDesc.ASPECIAL));
  138. m_elementFlags.put("BR",
  139. new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
  140. | ElemDesc.EMPTY | ElemDesc.BLOCK));
  141. m_elementFlags.put("BODY", new ElemDesc(0 | ElemDesc.BLOCK));
  142. m_elementFlags.put("ADDRESS",
  143. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  144. | ElemDesc.BLOCKFORMFIELDSET));
  145. m_elementFlags.put("DIV",
  146. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  147. | ElemDesc.BLOCKFORMFIELDSET));
  148. m_elementFlags.put("A", new ElemDesc(0 | ElemDesc.SPECIAL));
  149. m_elementFlags.put("MAP",
  150. new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
  151. | ElemDesc.BLOCK));
  152. m_elementFlags.put("AREA",
  153. new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
  154. m_elementFlags.put("LINK",
  155. new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.EMPTY
  156. | ElemDesc.BLOCK));
  157. m_elementFlags.put("IMG",
  158. new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
  159. | ElemDesc.EMPTY
  160. | ElemDesc.WHITESPACESENSITIVE));
  161. m_elementFlags.put("OBJECT",
  162. new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
  163. | ElemDesc.HEADMISC
  164. | ElemDesc.WHITESPACESENSITIVE));
  165. m_elementFlags.put("PARAM", new ElemDesc(0 | ElemDesc.EMPTY));
  166. m_elementFlags.put("HR",
  167. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  168. | ElemDesc.BLOCKFORMFIELDSET
  169. | ElemDesc.EMPTY));
  170. m_elementFlags.put("P",
  171. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  172. | ElemDesc.BLOCKFORMFIELDSET));
  173. m_elementFlags.put("H1",
  174. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  175. m_elementFlags.put("H2",
  176. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  177. m_elementFlags.put("H3",
  178. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  179. m_elementFlags.put("H4",
  180. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  181. m_elementFlags.put("H5",
  182. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  183. m_elementFlags.put("H6",
  184. new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
  185. m_elementFlags.put("PRE",
  186. new ElemDesc(0 | ElemDesc.PREFORMATTED
  187. | ElemDesc.BLOCK));
  188. m_elementFlags.put("Q",
  189. new ElemDesc(0 | ElemDesc.SPECIAL
  190. | ElemDesc.ASPECIAL));
  191. m_elementFlags.put("BLOCKQUOTE",
  192. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  193. | ElemDesc.BLOCKFORMFIELDSET));
  194. m_elementFlags.put("INS", new ElemDesc(0));
  195. m_elementFlags.put("DEL", new ElemDesc(0));
  196. m_elementFlags.put("DL",
  197. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  198. | ElemDesc.BLOCKFORMFIELDSET));
  199. m_elementFlags.put("DT", new ElemDesc(0 | ElemDesc.BLOCK));
  200. m_elementFlags.put("DD", new ElemDesc(0 | ElemDesc.BLOCK));
  201. m_elementFlags.put("OL",
  202. new ElemDesc(0 | ElemDesc.LIST | ElemDesc.BLOCK));
  203. m_elementFlags.put("UL",
  204. new ElemDesc(0 | ElemDesc.LIST | ElemDesc.BLOCK));
  205. m_elementFlags.put("LI", new ElemDesc(0 | ElemDesc.BLOCK));
  206. m_elementFlags.put("FORM", new ElemDesc(0 | ElemDesc.BLOCK));
  207. m_elementFlags.put("LABEL", new ElemDesc(0 | ElemDesc.FORMCTRL));
  208. m_elementFlags.put("INPUT",
  209. new ElemDesc(0 | ElemDesc.FORMCTRL
  210. | ElemDesc.INLINELABEL | ElemDesc.EMPTY));
  211. m_elementFlags.put("SELECT",
  212. new ElemDesc(0 | ElemDesc.FORMCTRL
  213. | ElemDesc.INLINELABEL));
  214. m_elementFlags.put("OPTGROUP", new ElemDesc(0));
  215. m_elementFlags.put("OPTION", new ElemDesc(0));
  216. m_elementFlags.put("TEXTAREA",
  217. new ElemDesc(0 | ElemDesc.FORMCTRL
  218. | ElemDesc.INLINELABEL));
  219. m_elementFlags.put("FIELDSET",
  220. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM));
  221. m_elementFlags.put("LEGEND", new ElemDesc(0));
  222. m_elementFlags.put("BUTTON",
  223. new ElemDesc(0 | ElemDesc.FORMCTRL
  224. | ElemDesc.INLINELABEL));
  225. m_elementFlags.put("TABLE",
  226. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  227. | ElemDesc.BLOCKFORMFIELDSET));
  228. m_elementFlags.put("CAPTION", new ElemDesc(0 | ElemDesc.BLOCK));
  229. m_elementFlags.put("THEAD", new ElemDesc(0 | ElemDesc.BLOCK));
  230. m_elementFlags.put("TFOOT", new ElemDesc(0 | ElemDesc.BLOCK));
  231. m_elementFlags.put("TBODY", new ElemDesc(0 | ElemDesc.BLOCK));
  232. m_elementFlags.put("COLGROUP", new ElemDesc(0 | ElemDesc.BLOCK));
  233. m_elementFlags.put("COL",
  234. new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
  235. m_elementFlags.put("TR", new ElemDesc(0 | ElemDesc.BLOCK));
  236. m_elementFlags.put("TH", new ElemDesc(0));
  237. m_elementFlags.put("TD", new ElemDesc(0));
  238. m_elementFlags.put("HEAD",
  239. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.HEADELEM));
  240. m_elementFlags.put("TITLE", new ElemDesc(0 | ElemDesc.BLOCK));
  241. m_elementFlags.put("BASE",
  242. new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
  243. m_elementFlags.put("META",
  244. new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.EMPTY
  245. | ElemDesc.BLOCK));
  246. m_elementFlags.put("STYLE",
  247. new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.RAW
  248. | ElemDesc.BLOCK));
  249. m_elementFlags.put("SCRIPT",
  250. new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
  251. | ElemDesc.HEADMISC | ElemDesc.RAW));
  252. m_elementFlags.put("NOSCRIPT",
  253. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  254. | ElemDesc.BLOCKFORMFIELDSET));
  255. m_elementFlags.put("HTML", new ElemDesc(0 | ElemDesc.BLOCK));
  256. // From "John Ky" <hand@syd.speednet.com.au
  257. // Transitional Document Type Definition ()
  258. // file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/sgml/loosedtd.html#basefont
  259. m_elementFlags.put("FONT", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  260. // file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/present/graphics.html#edef-STRIKE
  261. m_elementFlags.put("S", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  262. m_elementFlags.put("STRIKE", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  263. // file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/present/graphics.html#edef-U
  264. m_elementFlags.put("U", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  265. // From "John Ky" <hand@syd.speednet.com.au
  266. m_elementFlags.put("NOBR", new ElemDesc(0 | ElemDesc.FONTSTYLE));
  267. // HTML 4.0, section 16.5
  268. m_elementFlags.put("IFRAME",
  269. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  270. | ElemDesc.BLOCKFORMFIELDSET));
  271. // NS4 extensions
  272. m_elementFlags.put("LAYER",
  273. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  274. | ElemDesc.BLOCKFORMFIELDSET));
  275. m_elementFlags.put("ILAYER",
  276. new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
  277. | ElemDesc.BLOCKFORMFIELDSET));
  278. ElemDesc elemDesc;
  279. elemDesc = (ElemDesc) m_elementFlags.get("AREA");
  280. elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  281. elemDesc.setAttr("NOHREF", ElemDesc.ATTREMPTY);
  282. elemDesc = (ElemDesc) m_elementFlags.get("BASE");
  283. elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  284. elemDesc = (ElemDesc) m_elementFlags.get("BLOCKQUOTE");
  285. elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  286. elemDesc = (ElemDesc) m_elementFlags.get("Q");
  287. elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  288. elemDesc = (ElemDesc) m_elementFlags.get("INS");
  289. elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  290. elemDesc = (ElemDesc) m_elementFlags.get("DEL");
  291. elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  292. elemDesc = (ElemDesc) m_elementFlags.get("A");
  293. elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  294. elemDesc.setAttr("NAME", ElemDesc.ATTRURL);
  295. elemDesc = (ElemDesc) m_elementFlags.get("LINK");
  296. elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  297. elemDesc = (ElemDesc) m_elementFlags.get("INPUT");
  298. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  299. elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  300. elemDesc.setAttr("CHECKED", ElemDesc.ATTREMPTY);
  301. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  302. elemDesc.setAttr("ISMAP", ElemDesc.ATTREMPTY);
  303. elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
  304. elemDesc = (ElemDesc) m_elementFlags.get("SELECT");
  305. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  306. elemDesc.setAttr("MULTIPLE", ElemDesc.ATTREMPTY);
  307. elemDesc = (ElemDesc) m_elementFlags.get("OPTGROUP");
  308. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  309. elemDesc = (ElemDesc) m_elementFlags.get("OPTION");
  310. elemDesc.setAttr("SELECTED", ElemDesc.ATTREMPTY);
  311. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  312. elemDesc = (ElemDesc) m_elementFlags.get("TEXTAREA");
  313. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  314. elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
  315. elemDesc = (ElemDesc) m_elementFlags.get("BUTTON");
  316. elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  317. elemDesc = (ElemDesc) m_elementFlags.get("SCRIPT");
  318. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  319. elemDesc.setAttr("FOR", ElemDesc.ATTRURL);
  320. elemDesc.setAttr("DEFER", ElemDesc.ATTREMPTY);
  321. elemDesc = (ElemDesc) m_elementFlags.get("IMG");
  322. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  323. elemDesc.setAttr("LONGDESC", ElemDesc.ATTRURL);
  324. elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  325. elemDesc.setAttr("ISMAP", ElemDesc.ATTREMPTY);
  326. elemDesc = (ElemDesc) m_elementFlags.get("OBJECT");
  327. elemDesc.setAttr("CLASSID", ElemDesc.ATTRURL);
  328. elemDesc.setAttr("CODEBASE", ElemDesc.ATTRURL);
  329. elemDesc.setAttr("DATA", ElemDesc.ATTRURL);
  330. elemDesc.setAttr("ARCHIVE", ElemDesc.ATTRURL);
  331. elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  332. elemDesc.setAttr("DECLARE", ElemDesc.ATTREMPTY);
  333. elemDesc = (ElemDesc) m_elementFlags.get("FORM");
  334. elemDesc.setAttr("ACTION", ElemDesc.ATTRURL);
  335. elemDesc = (ElemDesc) m_elementFlags.get("HEAD");
  336. elemDesc.setAttr("PROFILE", ElemDesc.ATTRURL);
  337. // Attribution to: "Voytenko, Dimitry" <DVoytenko@SECTORBASE.COM>
  338. elemDesc = (ElemDesc) m_elementFlags.get("FRAME");
  339. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  340. elemDesc.setAttr("LONGDESC", ElemDesc.ATTRURL);
  341. // HTML 4.0, section 16.5
  342. elemDesc = (ElemDesc) m_elementFlags.get("IFRAME");
  343. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  344. elemDesc.setAttr("LONGDESC", ElemDesc.ATTRURL);
  345. // NS4 extensions
  346. elemDesc = (ElemDesc) m_elementFlags.get("LAYER");
  347. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  348. elemDesc = (ElemDesc) m_elementFlags.get("ILAYER");
  349. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  350. elemDesc = (ElemDesc) m_elementFlags.get("DIV");
  351. elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  352. }
  353. /**
  354. * Dummy element for elements not found.
  355. */
  356. static private ElemDesc m_dummy = new ElemDesc(0 | ElemDesc.BLOCK);
  357. /** True if URLs should be specially escaped with the %xx form. */
  358. private boolean m_specialEscapeURLs = true;
  359. /** True if the META tag should be omitted. */
  360. private boolean m_omitMetaTag = false;
  361. /**
  362. * Tells if the formatter should use special URL escaping.
  363. *
  364. * @param bool True if URLs should be specially escaped with the %xx form.
  365. */
  366. public void setSpecialEscapeURLs(boolean bool)
  367. {
  368. m_specialEscapeURLs = bool;
  369. }
  370. /**
  371. * Tells if the formatter should omit the META tag.
  372. *
  373. * @param bool True if the META tag should be omitted.
  374. */
  375. public void setOmitMetaTag(boolean bool)
  376. {
  377. m_omitMetaTag = bool;
  378. }
  379. /**
  380. * Specifies an output format for this serializer. It the
  381. * serializer has already been associated with an output format,
  382. * it will switch to the new format. This method should not be
  383. * called while the serializer is in the process of serializing
  384. * a document.
  385. *
  386. * @param format The output format to use
  387. */
  388. public void setOutputFormat(Properties format)
  389. {
  390. m_specialEscapeURLs =
  391. OutputProperties.getBooleanProperty(OutputProperties.S_USE_URL_ESCAPING,
  392. format);
  393. m_omitMetaTag =
  394. OutputProperties.getBooleanProperty(OutputProperties.S_OMIT_META_TAG,
  395. format);
  396. super.setOutputFormat(format);
  397. }
  398. /**
  399. * Tells if the formatter should use special URL escaping.
  400. *
  401. * @return True if URLs should be specially escaped with the %xx form.
  402. */
  403. public boolean getSpecialEscapeURLs()
  404. {
  405. return m_specialEscapeURLs;
  406. }
  407. /**
  408. * Tells if the formatter should omit the META tag.
  409. *
  410. * @return True if the META tag should be omitted.
  411. */
  412. public boolean getOmitMetaTag()
  413. {
  414. return m_omitMetaTag;
  415. }
  416. /**
  417. * Get a description of the given element.
  418. *
  419. * @param name non-null name of element, case insensitive.
  420. *
  421. * @return non-null reference to ElemDesc, which may be m_dummy if no
  422. * element description matches the given name.
  423. */
  424. ElemDesc getElemDesc(String name)
  425. {
  426. if (null != name)
  427. {
  428. Object obj = m_elementFlags.get(name);
  429. if (null != obj)
  430. return (ElemDesc) obj;
  431. }
  432. return m_dummy;
  433. }
  434. /**
  435. * Default constructor.
  436. */
  437. public SerializerToHTML()
  438. {
  439. super();
  440. m_charInfo = m_htmlcharInfo;
  441. }
  442. /** The name of the current element. */
  443. private String m_currentElementName = null;
  444. /**
  445. * Receive notification of the beginning of a document.
  446. *
  447. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  448. * wrapping another exception.
  449. *
  450. * @throws org.xml.sax.SAXException
  451. */
  452. public void startDocument() throws org.xml.sax.SAXException
  453. {
  454. m_needToOutputDocTypeDecl = true;
  455. m_startNewLine = false;
  456. m_shouldNotWriteXMLHeader = true;
  457. if (true == m_needToOutputDocTypeDecl)
  458. {
  459. if ((null != m_doctypeSystem) || (null != m_doctypePublic))
  460. {
  461. accum("<!DOCTYPE HTML");
  462. if (null != m_doctypePublic)
  463. {
  464. accum(" PUBLIC \"");
  465. accum(m_doctypePublic);
  466. accum("\"");
  467. }
  468. if (null != m_doctypeSystem)
  469. {
  470. if (null == m_doctypePublic)
  471. accum(" SYSTEM \"");
  472. else
  473. accum(" \"");
  474. accum(m_doctypeSystem);
  475. accum("\"");
  476. }
  477. accum(">");
  478. outputLineSep();
  479. }
  480. }
  481. m_needToOutputDocTypeDecl = false;
  482. }
  483. /**
  484. * Receive notification of the beginning of an element.
  485. *
  486. *
  487. * @param namespaceURI
  488. * @param localName
  489. * @param name The element type name.
  490. * @param atts The attributes attached to the element, if any.
  491. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  492. * wrapping another exception.
  493. * @see #endElement
  494. * @see org.xml.sax.AttributeList
  495. */
  496. public void startElement(
  497. String namespaceURI, String localName, String name, Attributes atts)
  498. throws org.xml.sax.SAXException
  499. {
  500. // System.out.println("SerializerToHTML#startElement("+namespaceURI+", "+localName+", "+name+", ...);");
  501. if (null != namespaceURI && namespaceURI.length() > 0)
  502. {
  503. super.startElement(namespaceURI, localName, name, atts);
  504. return;
  505. }
  506. boolean savedDoIndent = m_doIndent;
  507. boolean noLineBreak;
  508. writeParentTagEnd();
  509. pushState(
  510. namespaceURI, localName,
  511. m_cdataSectionNames, m_cdataSectionStates);
  512. // pushState(namespaceURI, localName, m_format.getNonEscapingElements(),
  513. // m_disableOutputEscapingStates);
  514. ElemDesc elemDesc = getElemDesc(name);
  515. // ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
  516. boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
  517. boolean isHeadElement = elemDesc.is(ElemDesc.HEADELEM);
  518. // boolean isWhiteSpaceSensitive = elemDesc.is(ElemDesc.WHITESPACESENSITIVE);
  519. if (m_ispreserve)
  520. m_ispreserve = false;
  521. else if (m_doIndent && (null != m_currentElementName)
  522. && (!m_inBlockElem || isBlockElement)
  523. /* && !isWhiteSpaceSensitive */
  524. )
  525. {
  526. m_startNewLine = true;
  527. indent(m_currentIndent);
  528. }
  529. m_inBlockElem = !isBlockElement;
  530. m_isRawStack.push(elemDesc.is(ElemDesc.RAW));
  531. m_currentElementName = name;
  532. // m_parents.push(m_currentElementName);
  533. this.accum('<');
  534. this.accum(name);
  535. int nAttrs = atts.getLength();
  536. for (int i = 0; i < nAttrs; i++)
  537. {
  538. processAttribute(atts.getQName(i), elemDesc, atts.getValue(i));
  539. }
  540. // Flag the current element as not yet having any children.
  541. openElementForChildren();
  542. m_currentIndent += this.m_indentAmount;
  543. m_isprevtext = false;
  544. m_doIndent = savedDoIndent;
  545. if (isHeadElement)
  546. {
  547. writeParentTagEnd();
  548. if (!m_omitMetaTag)
  549. {
  550. if (m_doIndent)
  551. indent(m_currentIndent);
  552. accum(
  553. "<META http-equiv=\"Content-Type\" content=\"text/html; charset=");
  554. // String encoding = Encodings.getMimeEncoding(m_encoding).toLowerCase();
  555. String encoding = Encodings.getMimeEncoding(m_encoding);
  556. accum(encoding);
  557. accum('"');
  558. accum('>');
  559. }
  560. }
  561. }
  562. /**
  563. * Receive notification of the end of an element.
  564. *
  565. *
  566. * @param namespaceURI
  567. * @param localName
  568. * @param name The element type name
  569. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  570. * wrapping another exception.
  571. */
  572. public void endElement(String namespaceURI, String localName, String name)
  573. throws org.xml.sax.SAXException
  574. {
  575. // System.out.println("SerializerToHTML#endElement("+namespaceURI+", "+localName+", "+name+");");
  576. if (null != namespaceURI && namespaceURI.length() > 0)
  577. {
  578. super.endElement(namespaceURI, localName, name);
  579. return;
  580. }
  581. m_currentIndent -= this.m_indentAmount;
  582. boolean hasChildNodes = childNodesWereAdded();
  583. // System.out.println(m_currentElementName);
  584. // m_parents.pop();
  585. m_isRawStack.pop();
  586. ElemDesc elemDesc = getElemDesc(name);
  587. // ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
  588. boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
  589. boolean shouldIndent = false;
  590. if (m_ispreserve)
  591. {
  592. m_ispreserve = false;
  593. }
  594. else if (m_doIndent && (!m_inBlockElem || isBlockElement))
  595. {
  596. m_startNewLine = true;
  597. shouldIndent = true;
  598. // indent(m_currentIndent);
  599. }
  600. m_inBlockElem = !isBlockElement;
  601. if (hasChildNodes)
  602. {
  603. if (shouldIndent)
  604. indent(m_currentIndent);
  605. this.accum("</");
  606. this.accum(name);
  607. this.accum('>');
  608. m_currentElementName = name;
  609. }
  610. else
  611. {
  612. if (!elemDesc.is(ElemDesc.EMPTY))
  613. {
  614. this.accum('>');
  615. // As per Dave/Paul recommendation 12/06/2000
  616. // if (shouldIndent)
  617. // indent(m_currentIndent);
  618. this.accum('<');
  619. this.accum('/');
  620. this.accum(name);
  621. this.accum('>');
  622. }
  623. else
  624. {
  625. this.accum('>');
  626. }
  627. }
  628. if (elemDesc.is(ElemDesc.WHITESPACESENSITIVE))
  629. m_ispreserve = true;
  630. if (hasChildNodes)
  631. {
  632. if (!m_preserves.isEmpty())
  633. m_preserves.pop();
  634. }
  635. m_isprevtext = false;
  636. // m_disableOutputEscapingStates.pop();
  637. m_cdataSectionStates.pop();
  638. }
  639. /**
  640. * Process an attribute.
  641. * @param name The name of the attribute.
  642. * @param elemDesc non-null reference to the owning element description.
  643. * @param value The value of the attribute.
  644. *
  645. * @throws org.xml.sax.SAXException
  646. */
  647. protected void processAttribute(
  648. String name, ElemDesc elemDesc, String value)
  649. throws org.xml.sax.SAXException
  650. {
  651. this.accum(' ');
  652. if (((value.length() == 0) || value.equalsIgnoreCase(name))
  653. && elemDesc.isAttrFlagSet(name, ElemDesc.ATTREMPTY))
  654. {
  655. this.accum(name);
  656. }
  657. else
  658. {
  659. this.accum(name);
  660. this.accum('=');
  661. this.accum('\"');
  662. if (elemDesc.isAttrFlagSet(name, ElemDesc.ATTRURL))
  663. writeAttrURI(value, m_specialEscapeURLs);
  664. else
  665. writeAttrString(value, this.m_encoding);
  666. this.accum('\"');
  667. }
  668. }
  669. /**
  670. * Tell if a character is an ASCII digit.
  671. */
  672. private boolean isASCIIDigit(char c)
  673. {
  674. return (c >= '0' && c <= '9');
  675. }
  676. /**
  677. * Make an integer into an HH hex value.
  678. * Does no checking on the size of the input, since this
  679. * is only meant to be used locally by writeAttrURI.
  680. *
  681. * @param i must be a value less than 255.
  682. *
  683. * @return should be a two character string.
  684. */
  685. private String makeHHString(int i)
  686. {
  687. String s = Integer.toHexString(i).toUpperCase();
  688. if(s.length() == 1)
  689. {
  690. s = "0"+s;
  691. }
  692. return s;
  693. }
  694. /**
  695. * Dmitri Ilyin: Makes sure if the String is HH encoded sign.
  696. * @param str must be 2 characters long
  697. *
  698. * @return true or false
  699. */
  700. private boolean isHHSign(String str)
  701. {
  702. boolean sign = true;
  703. try {
  704. char r = (char)Integer.parseInt(str,16);
  705. } catch (NumberFormatException e) {
  706. sign = false;
  707. }
  708. return sign;
  709. }
  710. /**
  711. * Write the specified <var>string</var> after substituting non ASCII characters,
  712. * with <CODE>%HH</CODE>, where HH is the hex of the byte value.
  713. *
  714. * @param string String to convert to XML format.
  715. * @param doURLEscaping True if we should try to encode as
  716. * per http://www.ietf.org/rfc/rfc2396.txt.
  717. *
  718. * @throws org.xml.sax.SAXException if a bad surrogate pair is detected.
  719. */
  720. public void writeAttrURI(String string, boolean doURLEscaping)
  721. throws org.xml.sax.SAXException
  722. {
  723. // http://www.ietf.org/rfc/rfc2396.txt says:
  724. // A URI is always in an "escaped" form, since escaping or unescaping a
  725. // completed URI might change its semantics. Normally, the only time
  726. // escape encodings can safely be made is when the URI is being created
  727. // from its component parts; each component may have its own set of
  728. // characters that are reserved, so only the mechanism responsible for
  729. // generating or interpreting that component can determine whether or
  730. // not escaping a character will change its semantics. Likewise, a URI
  731. // must be separated into its components before the escaped characters
  732. // within those components can be safely decoded.
  733. //
  734. // ...So we do our best to do limited escaping of the URL, without
  735. // causing damage. If the URL is already properly escaped, in theory, this
  736. // function should not change the string value.
  737. char[] stringArray = string.toCharArray();
  738. int len = stringArray.length;
  739. for (int i = 0; i < len; i++)
  740. {
  741. char ch = stringArray[i];
  742. if ((ch < 32) || (ch > 126))
  743. {
  744. if (doURLEscaping)
  745. {
  746. // Encode UTF16 to UTF8.
  747. // Reference is Unicode, A Primer, by Tony Graham.
  748. // Page 92.
  749. // Note that Kay doesn't escape 0x20...
  750. // if(ch == 0x20) // Not sure about this... -sb
  751. // {
  752. // accum(ch);
  753. // }
  754. // else
  755. if(ch <= 0x7F)
  756. {
  757. accum('%');
  758. accum(makeHHString(ch));
  759. }
  760. else if(ch <= 0x7FF)
  761. {
  762. // Clear low 6 bits before rotate, put high 4 bits in low byte,
  763. // and set two high bits.
  764. int high = (ch >> 6) | 0xC0;
  765. int low = (ch & 0x3F) | 0x80; // First 6 bits, + high bit
  766. accum('%');
  767. accum(makeHHString(high));
  768. accum('%');
  769. accum(makeHHString(low));
  770. }
  771. else if( isUTF16Surrogate(ch) ) // high surrogate
  772. {
  773. // I'm sure this can be done in 3 instructions, but I choose
  774. // to try and do it exactly like it is done in the book, at least
  775. // until we are sure this is totally clean. I don't think performance
  776. // is a big issue with this particular function, though I could be
  777. // wrong. Also, the stuff below clearly does more masking than
  778. // it needs to do.
  779. // Clear high 6 bits.
  780. int highSurrogate = ((int) ch) & 0x03FF;
  781. // Middle 4 bits (wwww) + 1
  782. // "Note that the value of wwww from the high surrogate bit pattern
  783. // is incremented to make the uuuuu bit pattern in the scalar value
  784. // so the surrogate pair don't address the BMP."
  785. int wwww = ((highSurrogate & 0x03C0) >> 6);
  786. int uuuuu = wwww+1;
  787. // next 4 bits
  788. int zzzz = (highSurrogate & 0x003C) >> 2;
  789. // low 2 bits
  790. int yyyyyy = ((highSurrogate & 0x0003) << 4) & 0x30;
  791. // Get low surrogate character.
  792. ch = stringArray[++i];
  793. // Clear high 6 bits.
  794. int lowSurrogate = ((int) ch) & 0x03FF;
  795. // put the middle 4 bits into the bottom of yyyyyy (byte 3)
  796. yyyyyy = yyyyyy | ((lowSurrogate & 0x03C0) >> 6);
  797. // bottom 6 bits.
  798. int xxxxxx = (lowSurrogate & 0x003F);
  799. int byte1 = 0xF0 | (uuuuu >> 2); // top 3 bits of uuuuu
  800. int byte2 = 0x80 | (((uuuuu & 0x03) << 4) & 0x30) | zzzz;
  801. int byte3 = 0x80 | yyyyyy;
  802. int byte4 = 0x80 | xxxxxx;
  803. accum('%');
  804. accum(makeHHString(byte1));
  805. accum('%');
  806. accum(makeHHString(byte2));
  807. accum('%');
  808. accum(makeHHString(byte3));
  809. accum('%');
  810. accum(makeHHString(byte4));
  811. }
  812. else
  813. {
  814. int high = (ch >> 12) | 0xE0; // top 4 bits
  815. int middle = ((ch & 0x0FC0) >> 6) | 0x80; // middle 6 bits
  816. int low = (ch & 0x3F) | 0x80; // First 6 bits, + high bit
  817. accum('%');
  818. accum(makeHHString(high));
  819. accum('%');
  820. accum(makeHHString(middle));
  821. accum('%');
  822. accum(makeHHString(low));
  823. }
  824. }
  825. else if (canConvert(ch))
  826. {
  827. accum(ch);
  828. }
  829. else
  830. {
  831. accum("&#");
  832. accum(Integer.toString(ch));
  833. accum(';');
  834. }
  835. }
  836. else if('%' == ch)
  837. {
  838. // If the character is a '%' number number, try to avoid double-escaping.
  839. // There is a question if this is legal behavior.
  840. // Dmitri Ilyin: to check if '%' number number is invalid. It must be checked if %xx is a sign, that would be encoded
  841. // The encoded signes are in Hex form. So %xx my be in form %3C that is "<" sign. I will try to change here a little.
  842. // if( ((i+2) < len) && isASCIIDigit(stringArray[i+1]) && isASCIIDigit(stringArray[i+2]) )
  843. // We are no longer escaping '%'
  844. /* if ( ((i+2) < len) && isHHSign(new String(stringArray,i+1,2)) )
  845. {
  846. accum(ch);
  847. }
  848. else
  849. {
  850. if (doURLEscaping)
  851. {
  852. accum('%');
  853. accum(makeHHString(ch));
  854. }
  855. else*/
  856. accum(ch);
  857. // }
  858. }
  859. // Since http://www.ietf.org/rfc/rfc2396.txt refers to the URI grammar as
  860. // not allowing quotes in the URI proper syntax, nor in the fragment
  861. // identifier, we believe that it's OK to double escape quotes.
  862. else if (ch == '"')
  863. {
  864. // Mike Kay encodes this as ", so he may know something I don't?
  865. if (doURLEscaping)
  866. accum("%22");
  867. else
  868. accum("""); // we have to escape this, I guess.
  869. }
  870. else
  871. {
  872. accum(ch);
  873. }
  874. }
  875. }
  876. /**
  877. * Writes the specified <var>string</var> after substituting <VAR>specials</VAR>,
  878. * and UTF-16 surrogates for character references <CODE>&#xnn</CODE>.
  879. *
  880. * @param string String to convert to XML format.
  881. * @param encoding CURRENTLY NOT IMPLEMENTED.
  882. *
  883. * @throws org.xml.sax.SAXException
  884. */
  885. public void writeAttrString(String string, String encoding)
  886. throws org.xml.sax.SAXException
  887. {
  888. final char chars[] = string.toCharArray();
  889. final int strLen = chars.length;
  890. for (int i = 0; i < strLen; i++)
  891. {
  892. char ch = chars[i];
  893. // System.out.println("SPECIALSSIZE: "+SPECIALSSIZE);
  894. // System.out.println("ch: "+(int)ch);
  895. // System.out.println("m_maxCharacter: "+(int)m_maxCharacter);
  896. // System.out.println("m_attrCharsMap[ch]: "+(int)m_attrCharsMap[ch]);
  897. if (canConvert(ch) && (!m_charInfo.isSpecial(ch)))
  898. {
  899. accum(ch);
  900. }
  901. else if ('<' == ch || '>' == ch)
  902. {
  903. accum(ch); // no escaping in this case, as specified in 15.2
  904. }
  905. else if (('&' == ch) && ((i + 1) < strLen) && ('{' == chars[i + 1]))
  906. {
  907. accum(ch); // no escaping in this case, as specified in 15.2
  908. }
  909. else
  910. {
  911. int pos = accumDefaultEntity(ch, i, chars, strLen, false);
  912. if (i != pos)
  913. {
  914. i = pos - 1;
  915. }
  916. else
  917. {
  918. if (isUTF16Surrogate(ch))
  919. {
  920. try
  921. {
  922. i = writeUTF16Surrogate(ch, chars, i, strLen);
  923. }
  924. catch(IOException ioe)
  925. {
  926. throw new SAXException(ioe);
  927. }
  928. }
  929. // The next is kind of a hack to keep from escaping in the case
  930. // of Shift_JIS and the like.
  931. /*
  932. else if ((ch < m_maxCharacter) && (m_maxCharacter == 0xFFFF)
  933. && (ch != 160))
  934. {
  935. accum(ch); // no escaping in this case
  936. }
  937. else
  938. */
  939. String entityName = m_charInfo.getEntityNameForChar(ch);
  940. if (null != entityName)
  941. {
  942. accum('&');
  943. accum(entityName);
  944. accum(';');
  945. }
  946. else if (canConvert(ch))
  947. {
  948. accum(ch); // no escaping in this case
  949. }
  950. else
  951. {
  952. accum("&#");
  953. accum(Integer.toString(ch));
  954. accum(';');
  955. }
  956. }
  957. }
  958. }
  959. }
  960. /**
  961. * Copy an entity into the accumulation buffer.
  962. *
  963. * @param s The name of the entity.
  964. * @param pos unused.
  965. *
  966. * @return The pos argument.
  967. *
  968. * @throws org.xml.sax.SAXException
  969. */
  970. private int copyEntityIntoBuf(String s, int pos)
  971. throws org.xml.sax.SAXException
  972. {
  973. int l = s.length();
  974. accum('&');
  975. for (int i = 0; i < l; i++)
  976. {
  977. accum(s.charAt(i));
  978. }
  979. accum(';');
  980. return pos;
  981. }
  982. /**
  983. * Receive notification of character data.
  984. *
  985. * <p>The Parser will call this method to report each chunk of
  986. * character data. SAX parsers may return all contiguous character
  987. * data in a single chunk, or they may split it into several
  988. * chunks; however, all of the characters in any single event
  989. * must come from the same external entity, so that the Locator
  990. * provides useful information.</p>
  991. *
  992. * <p>The application must not attempt to read from the array
  993. * outside of the specified range.</p>
  994. *
  995. * <p>Note that some parsers will report whitespace using the
  996. * ignorableWhitespace() method rather than this one (validating
  997. * parsers must do so).</p>
  998. *
  999. * @param chars The characters from the XML document.
  1000. * @param start The start position in the array.
  1001. * @param length The number of characters to read from the array.
  1002. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  1003. * wrapping another exception.
  1004. * @see #ignorableWhitespace
  1005. * @see org.xml.sax.Locator
  1006. *
  1007. * @throws org.xml.sax.SAXException
  1008. */
  1009. public void characters(char chars[], int start, int length)
  1010. throws org.xml.sax.SAXException
  1011. {
  1012. if (m_isRawStack.peekOrFalse())
  1013. {
  1014. try
  1015. {
  1016. writeParentTagEnd();
  1017. m_ispreserve = true;
  1018. if (shouldIndent())
  1019. indent(m_currentIndent);
  1020. // this.accum("<![CDATA[");
  1021. // this.accum(chars, start, length);
  1022. writeNormalizedChars(chars, start, length, false);
  1023. // this.accum("]]>");
  1024. return;
  1025. }
  1026. catch (IOException ioe)
  1027. {
  1028. throw new org.xml.sax.SAXException(
  1029. XSLMessages.createXPATHMessage(
  1030. XPATHErrorResources.ER_OIERROR, null), ioe); //"IO error", ioe);
  1031. }
  1032. }
  1033. else
  1034. {
  1035. super.characters(chars, start, length);
  1036. }
  1037. }
  1038. /**
  1039. * Receive notification of cdata.
  1040. *
  1041. * <p>The Parser will call this method to report each chunk of
  1042. * character data. SAX parsers may return all contiguous character
  1043. * data in a single chunk, or they may split it into several
  1044. * chunks; however, all of the characters in any single event
  1045. * must come from the same external entity, so that the Locator
  1046. * provides useful information.</p>
  1047. *
  1048. * <p>The application must not attempt to read from the array
  1049. * outside of the specified range.</p>
  1050. *
  1051. * <p>Note that some parsers will report whitespace using the
  1052. * ignorableWhitespace() method rather than this one (validating
  1053. * parsers must do so).</p>
  1054. *
  1055. * @param ch The characters from the XML document.
  1056. * @param start The start position in the array.
  1057. * @param length The number of characters to read from the array.
  1058. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  1059. * wrapping another exception.
  1060. * @see #ignorableWhitespace
  1061. * @see org.xml.sax.Locator
  1062. *
  1063. * @throws org.xml.sax.SAXException
  1064. */
  1065. public void cdata(char ch[], int start, int length)
  1066. throws org.xml.sax.SAXException
  1067. {
  1068. if ((null != m_currentElementName)
  1069. && (m_currentElementName.equalsIgnoreCase("SCRIPT")
  1070. || m_currentElementName.equalsIgnoreCase("STYLE")))
  1071. {
  1072. try
  1073. {
  1074. writeParentTagEnd();
  1075. m_ispreserve = true;
  1076. if (shouldIndent())
  1077. indent(m_currentIndent);
  1078. // this.accum(ch, start, length);
  1079. writeNormalizedChars(ch, start, length, true);
  1080. }
  1081. catch (IOException ioe)
  1082. {
  1083. throw new org.xml.sax.SAXException(
  1084. XSLMessages.createXPATHMessage(
  1085. XPATHErrorResources.ER_OIERROR, null), ioe); //"IO error", ioe);
  1086. }
  1087. }
  1088. /*
  1089. else if(m_stripCData) // should normally always be false
  1090. {
  1091. try
  1092. {
  1093. writeParentTagEnd();
  1094. m_ispreserve = true;
  1095. if (shouldIndent())
  1096. indent(m_currentIndent);
  1097. // this.accum("<![CDATA[");
  1098. this.accum(ch, start, length);
  1099. // this.accum("]]>");
  1100. }
  1101. catch(IOException ioe)
  1102. {
  1103. throw new org.xml.sax.SAXException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_OIERROR, null),ioe); //"IO error", ioe);
  1104. }
  1105. }
  1106. */
  1107. else
  1108. {
  1109. super.cdata(ch, start, length);
  1110. }
  1111. }
  1112. /**
  1113. * Receive notification of a processing instruction.
  1114. *
  1115. * @param target The processing instruction target.
  1116. * @param data The processing instruction data, or null if
  1117. * none was supplied.
  1118. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  1119. * wrapping another exception.
  1120. *
  1121. * @throws org.xml.sax.SAXException
  1122. */
  1123. public void processingInstruction(String target, String data)
  1124. throws org.xml.sax.SAXException
  1125. {
  1126. // Use a fairly nasty hack to tell if the next node is supposed to be
  1127. // unescaped text.
  1128. if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
  1129. {
  1130. startNonEscaping();
  1131. }
  1132. else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
  1133. {
  1134. endNonEscaping();
  1135. }
  1136. else
  1137. {
  1138. writeParentTagEnd();
  1139. if (shouldIndent())
  1140. indent(m_currentIndent);
  1141. this.accum("<?" + target);
  1142. if (data.length() > 0 &&!Character.isSpaceChar(data.charAt(0)))
  1143. this.accum(" ");
  1144. this.accum(data + ">"); // different from XML
  1145. // Always output a newline char if not inside of an
  1146. // element. The whitespace is not significant in that
  1147. // case.
  1148. if (m_elemStack.isEmpty())
  1149. outputLineSep();
  1150. m_startNewLine = true;
  1151. }
  1152. }
  1153. /**
  1154. * Receive notivication of a entityReference.
  1155. *
  1156. * @param name non-null reference to entity name string.
  1157. *
  1158. * @throws org.xml.sax.SAXException
  1159. */
  1160. public void entityReference(String name) throws org.xml.sax.SAXException
  1161. {
  1162. this.accum("&");
  1163. this.accum(name);
  1164. this.accum(";");
  1165. }
  1166. }