001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.om.NamePool;
004: import net.sf.saxon.om.NamespaceConstant;
005: import net.sf.saxon.trans.XPathException;
006: import net.sf.saxon.codenorm.Normalizer;
007:
008: import java.util.HashSet;
009:
010: /**
011: * This class performs URI escaping for the XHTML output method. The logic for performing escaping
012: * is the same as the HTML output method, but the way in which attributes are identified for escaping
013: * is different, because XHTML is case-sensitive.
014: */
015:
016: public class XHTMLURIEscaper extends HTMLURIEscaper {
017:
018: /**
019: * Table of attributes whose value is a URL
020: */
021:
022: private HashSet urlTable;
023:
024: private synchronized void buildURIAttributeTable() {
025: // Reuse the attribute table for all XHTMLEmitters sharing the same namepool
026: NamePool pool = getPipelineConfiguration().getConfiguration()
027: .getNamePool();
028: urlTable = (HashSet) pool.getClientData(this .getClass());
029: if (urlTable == null) {
030: urlTable = new HashSet(40);
031: pool.setClientData(this .getClass(), urlTable);
032: }
033: setUrlAttribute(pool, "form", "action");
034: setUrlAttribute(pool, "object", "archive");
035: setUrlAttribute(pool, "body", "background");
036: setUrlAttribute(pool, "q", "cite");
037: setUrlAttribute(pool, "blockquote", "cite");
038: setUrlAttribute(pool, "del", "cite");
039: setUrlAttribute(pool, "ins", "cite");
040: setUrlAttribute(pool, "object", "classid");
041: setUrlAttribute(pool, "object", "codebase");
042: setUrlAttribute(pool, "applet", "codebase");
043: setUrlAttribute(pool, "object", "data");
044: setUrlAttribute(pool, "button", "datasrc");
045: setUrlAttribute(pool, "div", "datasrc");
046: setUrlAttribute(pool, "input", "datasrc");
047: setUrlAttribute(pool, "object", "datasrc");
048: setUrlAttribute(pool, "select", "datasrc");
049: setUrlAttribute(pool, "span", "datasrc");
050: setUrlAttribute(pool, "table", "datasrc");
051: setUrlAttribute(pool, "textarea", "datasrc");
052: setUrlAttribute(pool, "script", "for");
053: setUrlAttribute(pool, "a", "href");
054: setUrlAttribute(pool, "a", "name"); // see second note in section B.2.1 of HTML 4 specification
055: setUrlAttribute(pool, "area", "href");
056: setUrlAttribute(pool, "link", "href");
057: setUrlAttribute(pool, "base", "href");
058: setUrlAttribute(pool, "img", "longdesc");
059: setUrlAttribute(pool, "frame", "longdesc");
060: setUrlAttribute(pool, "iframe", "longdesc");
061: setUrlAttribute(pool, "head", "profile");
062: setUrlAttribute(pool, "script", "src");
063: setUrlAttribute(pool, "input", "src");
064: setUrlAttribute(pool, "frame", "src");
065: setUrlAttribute(pool, "iframe", "src");
066: setUrlAttribute(pool, "img", "src");
067: setUrlAttribute(pool, "img", "usemap");
068: setUrlAttribute(pool, "input", "usemap");
069: setUrlAttribute(pool, "object", "usemap");
070: }
071:
072: private void setUrlAttribute(NamePool pool, String element,
073: String attribute) {
074: int elcode = pool
075: .allocate("", NamespaceConstant.XHTML, element)
076: & NamePool.FP_MASK;
077: int atcode = pool.allocate("", "", attribute)
078: & NamePool.FP_MASK;
079: Long key = new Long(((long) elcode) << 32 | (long) atcode);
080: urlTable.add(key);
081: }
082:
083: /**
084: * Determine whether a given attribute is a URL attribute
085: */
086:
087: private boolean isURLAttribute(int elcode, int atcode) {
088: elcode = elcode & NamePool.FP_MASK;
089: atcode = atcode & NamePool.FP_MASK;
090: Long key = new Long(((long) elcode) << 32 | (long) atcode);
091: return urlTable.contains(key);
092: }
093:
094: /**
095: * Do the real work of starting the document. This happens when the first
096: * content is written.
097: *
098: * @throws net.sf.saxon.trans.XPathException
099: *
100: */
101:
102: public void open() throws XPathException {
103: super .open();
104: if (escapeURIAttributes) {
105: buildURIAttributeTable();
106: }
107: }
108:
109: /**
110: * Notify an attribute. Attributes are notified after the startElement event, and before any
111: * children. Namespaces and attributes may be intermingled.
112: *
113: * @param nameCode The name of the attribute, as held in the name pool
114: * @param typeCode The type of the attribute, as held in the name pool
115: * @param properties Bit significant value. The following bits are defined:
116: * <dd>DISABLE_ESCAPING</dd> <dt>Disable escaping for this attribute</dt>
117: * <dd>NO_SPECIAL_CHARACTERS</dd> <dt>Attribute value contains no special characters</dt>
118: * @throws IllegalStateException: attempt to output an attribute when there is no open element
119: * start tag
120: */
121:
122: public void attribute(int nameCode, int typeCode,
123: CharSequence value, int locationId, int properties)
124: throws XPathException {
125: if (escapeURIAttributes
126: && isURLAttribute(currentElement, nameCode)
127: && (properties & ReceiverOptions.DISABLE_ESCAPING) == 0) {
128: CharSequence normalized = new Normalizer(Normalizer.C)
129: .normalize(value);
130: getUnderlyingReceiver()
131: .attribute(
132: nameCode,
133: typeCode,
134: HTMLURIEscaper.escapeURL(normalized),
135: locationId,
136: properties
137: | ReceiverOptions.DISABLE_CHARACTER_MAPS);
138: } else {
139: getUnderlyingReceiver().attribute(nameCode, typeCode,
140: value, locationId, properties);
141: }
142: }
143:
144: }
145:
146: //
147: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
148: // you may not use this file except in compliance with the License. You may obtain a copy of the
149: // License at http://www.mozilla.org/MPL/
150: //
151: // Software distributed under the License is distributed on an "AS IS" basis,
152: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
153: // See the License for the specific language governing rights and limitations under the License.
154: //
155: // The Original Code is: all this file.
156: //
157: // The Initial Developer of the Original Code is Michael H. Kay.
158: //
159: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
160: //
161: // Contributor(s): none.
162: //
|