001: /* ProcessingInstruction.java
002:
003: {{IS_NOTE
004:
005: Purpose:
006: Description:
007: History:
008: 2001/10/22 20:53:28, Create, Tom M. Yeh.
009: }}IS_NOTE
010:
011: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
012:
013: {{IS_RIGHT
014: This program is distributed under GPL Version 2.0 in the hope that
015: it will be useful, but WITHOUT ANY WARRANTY.
016: }}IS_RIGHT
017: */
018: package org.zkoss.idom;
019:
020: import java.util.Map;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.Collections;
024: import java.io.IOException;
025:
026: import org.zkoss.mesg.MCommon;
027: import org.zkoss.lang.Objects;
028: import org.zkoss.lang.Strings;
029: import org.zkoss.lang.SystemException;
030: import org.zkoss.util.Maps;
031: import org.zkoss.idom.impl.*;
032:
033: /**
034: * The iDOM processing instruction.
035: *
036: * @author tomyeh
037: */
038: public class ProcessingInstruction extends AbstractItem implements
039: org.w3c.dom.ProcessingInstruction {
040: /** The target. */
041: protected String _target;
042: /** The raw data. */
043: protected String _rawData;
044:
045: /** Constructor.
046: */
047: public ProcessingInstruction(String target, String data) {
048: setTarget(target);
049: setData(data);
050: }
051:
052: /** Constructor.
053: */
054: public ProcessingInstruction(String target, Map data) {
055: setTarget(target);
056: setData(data);
057: }
058:
059: /** Constructor.
060: */
061: protected ProcessingInstruction() {
062: }
063:
064: //-- ProcessingInstruction extras --//
065: public final String getTarget() {
066: return _target;
067: }
068:
069: public final void setTarget(String target) {
070: checkWritable();
071: if (!Objects.equals(_target, target)) {
072: Verifier.checkPITarget(target, getLocator());
073: _target = target;
074: setModified();
075: }
076: }
077:
078: public final String getData() {
079: return _rawData;
080: }
081:
082: public final void setData(String data) {
083: checkWritable();
084:
085: if (data == null)
086: data = "";
087:
088: if (!Objects.equals(_rawData, data)) {
089: _rawData = data;
090: setModified();
091: }
092: }
093:
094: /** Returns the parsed data in the form of Map (never null).
095: */
096: public final Map parseData() {
097: return parseToMap(null, getData());
098: }
099:
100: /**
101: * Sets the raw data with a data map.
102: * Each entry in the data map is a (name, value) pair.
103: *
104: * @exception org.zkoss.util.IllegalSyntaxException if name contains
105: * an invalid character: '=', ' ', '\'', '"'
106: */
107: public final void setData(Map data) {
108: final String notAllowed = "= '\"";
109: for (final Iterator it = data.keySet().iterator(); it.hasNext();) {
110: final String key = (String) it.next();
111: final int j = Strings.anyOf(key, notAllowed, 0);
112: if (j < key.length()) { //found
113: final char cc = key.charAt(j);
114: throw new SystemException(MCommon.ILLEGAL_CHAR, cc
115: + " (0x" + Integer.toHexString(cc) + ')');
116: }
117: }
118:
119: setData(Maps.toString(data, '"', ' '));
120: }
121:
122: /**
123: * Parses the raw data into a map.
124: * Each entry in the data map is a (name, value) pair.
125: * This method will convert a value to a number, either Integer
126: * or Double, if appropriate.
127: *
128: * <p>Most of characters are considered as ordinary (like 'a'),
129: * exception '"', '='
130: *
131: * <p>Example, the string wil cause ("a12", Intger(12)),
132: * ("b+3", null), ("345", null), ("c6", "abc=125&3?5"):<br>
133: * a12 =12 b+3 345 c6=\t'abc=125&3?5'
134: *
135: * @return the map (never null)
136: * @exception org.zkoss.util.IllegalSyntaxException if syntax erros
137: */
138: public static final Map parseToMap(Map map, String rawData) {
139: if (rawData == null || rawData.trim().length() == 0)
140: return map != null ? map : Collections.EMPTY_MAP;
141:
142: map = Maps.parse(map, rawData, ' ', '"');
143:
144: //" and other are not processed by SAXHandler,
145: //so we have to handle them here
146: for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
147: final Map.Entry me = (Map.Entry) it.next();
148: final String val = (String) me.getValue();
149: StringBuffer sb = null;
150: for (int i = 0, j = 0, len = val.length();;) {
151: int k = val.indexOf('&', j);
152: if (k < 0) {
153: if (sb != null)
154: me.setValue(sb.append(val.substring(i))
155: .toString());
156: break;
157: }
158:
159: int l = val.indexOf(';', k);
160: if (l >= 0) {
161: final char cc;
162: final String code = val.substring(k + 1, l);
163: if ("quot".equals(code)) {
164: cc = '"';
165: } else if ("amp".equals(code)) {
166: cc = '&';
167: } else if ("lt".equals(code)) {
168: cc = '<';
169: } else if ("gt".equals(code)) {
170: cc = '>';
171: } else {
172: //TODO: handle &#nnn; and more
173: j = l + 1;
174: continue; //ignore it
175: }
176:
177: if (sb == null)
178: sb = new StringBuffer(len);
179: sb.append(val.substring(i, k)).append(cc);
180: i = j = l + 1;
181: } else {
182: j = k + 1;
183: }
184: }
185: }
186:
187: return map;
188: }
189:
190: //-- Item --//
191: public final String getName() {
192: return getTarget();
193: }
194:
195: public final void setName(String name) {
196: setTarget(name);
197: }
198:
199: public final String getText() {
200: return getData();
201: }
202:
203: public final void setText(String text) {
204: setData(text);
205: }
206:
207: //-- Node --//
208: public final short getNodeType() {
209: return PROCESSING_INSTRUCTION_NODE;
210: }
211:
212: //-- org.w3c.dom.ProcessingInstruction --//
213:
214: //-- Object --//
215: public String toString() {
216: StringBuffer sb = new StringBuffer(64).append("[PI: ").append(
217: _target);
218: if (_rawData.length() > 0)
219: sb.append(' ').append(_rawData);
220: return sb.append(']').toString();
221: }
222: }
|