comparison NGSrich_0.5.5/src/org/jdom/ProcessingInstruction.java @ 0:89ad0a9cca52 default tip

Uploaded
author pfrommolt
date Mon, 21 Nov 2011 08:12:19 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:89ad0a9cca52
1 /*--
2
3 $Id: ProcessingInstruction.java,v 1.47 2007/11/10 05:28:59 jhunter Exp $
4
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
6 All rights 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 disclaimer that follows
17 these conditions in the documentation and/or other materials
18 provided with the distribution.
19
20 3. The name "JDOM" must not be used to endorse or promote products
21 derived from this software without prior written permission. For
22 written permission, please contact <request_AT_jdom_DOT_org>.
23
24 4. Products derived from this software may not be called "JDOM", nor
25 may "JDOM" appear in their name, without prior written permission
26 from the JDOM Project Management <request_AT_jdom_DOT_org>.
27
28 In addition, we request (but do not require) that you include in the
29 end-user documentation provided with the redistribution and/or in the
30 software itself an acknowledgement equivalent to the following:
31 "This product includes software developed by the
32 JDOM Project (http://www.jdom.org/)."
33 Alternatively, the acknowledgment may be graphical using the logos
34 available at http://www.jdom.org/images/logos.
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 JDOM AUTHORS OR THE PROJECT
40 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 This software consists of voluntary contributions made by many
50 individuals on behalf of the JDOM Project and was originally
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53 on the JDOM Project, please see <http://www.jdom.org/>.
54
55 */
56
57 package org.jdom;
58
59 import java.util.*;
60
61 /**
62 * An XML processing instruction. Methods allow the user to obtain the target of
63 * the PI as well as its data. The data can always be accessed as a String or,
64 * if the data appears akin to an attribute list, can be retrieved as name/value
65 * pairs.
66 *
67 * @version $Revision: 1.47 $, $Date: 2007/11/10 05:28:59 $
68 * @author Brett McLaughlin
69 * @author Jason Hunter
70 * @author Steven Gould
71 */
72
73 public class ProcessingInstruction extends Content {
74
75 private static final String CVS_ID =
76 "@(#) $RCSfile: ProcessingInstruction.java,v $ $Revision: 1.47 $ $Date: 2007/11/10 05:28:59 $ $Name: jdom_1_1_1 $";
77
78 /** The target of the PI */
79 protected String target;
80
81 /** The data for the PI as a String */
82 protected String rawData;
83
84 /** The data for the PI in name/value pairs */
85 protected Map mapData;
86
87 /**
88 * Default, no-args constructor for implementations
89 * to use if needed.
90 */
91 protected ProcessingInstruction() { }
92
93 /**
94 * This will create a new <code>ProcessingInstruction</code>
95 * with the specified target and data.
96 *
97 * @param target <code>String</code> target of PI.
98 * @param data <code>Map</code> data for PI, in
99 * name/value pairs
100 * @throws IllegalTargetException if the given target is illegal
101 * as a processing instruction name.
102 */
103 public ProcessingInstruction(String target, Map data) {
104 setTarget(target);
105 setData(data);
106 }
107
108 /**
109 * This will create a new <code>ProcessingInstruction</code>
110 * with the specified target and data.
111 *
112 * @param target <code>String</code> target of PI.
113 * @param data <code>String</code> data for PI.
114 * @throws IllegalTargetException if the given target is illegal
115 * as a processing instruction name.
116 */
117 public ProcessingInstruction(String target, String data) {
118 setTarget(target);
119 setData(data);
120 }
121
122 /**
123 * This will set the target for the PI.
124 *
125 * @param newTarget <code>String</code> new target of PI.
126 * @return <code>ProcessingInstruction</code> - this PI modified.
127 */
128 public ProcessingInstruction setTarget(String newTarget) {
129 String reason;
130 if ((reason = Verifier.checkProcessingInstructionTarget(newTarget))
131 != null) {
132 throw new IllegalTargetException(newTarget, reason);
133 }
134
135 target = newTarget;
136 return this;
137 }
138
139 /**
140 * Returns the XPath 1.0 string value of this element, which is the
141 * data of this PI.
142 *
143 * @return the data of this PI
144 */
145 public String getValue() {
146 return rawData;
147 }
148
149
150 /**
151 * This will retrieve the target of the PI.
152 *
153 * @return <code>String</code> - target of PI.
154 */
155 public String getTarget() {
156 return target;
157 }
158
159 /**
160 * This will return the raw data from all instructions.
161 *
162 * @return <code>String</code> - data of PI.
163 */
164 public String getData() {
165 return rawData;
166 }
167
168 /**
169 * This will return a <code>List</code> containing the names of the
170 * "attribute" style pieces of name/value pairs in this PI's data.
171 *
172 * @return <code>List</code> - the <code>List</code> containing the
173 * "attribute" names.
174 */
175 public List getPseudoAttributeNames() {
176 Set mapDataSet = mapData.entrySet();
177 List nameList = new ArrayList();
178 for (Iterator i = mapDataSet.iterator(); i.hasNext();) {
179 String wholeSet = (i.next()).toString();
180 String attrName = wholeSet.substring(0,(wholeSet.indexOf("=")));
181 nameList.add(attrName);
182 }
183 return nameList;
184 }
185
186 /**
187 * This will set the raw data for the PI.
188 *
189 * @param data <code>String</code> data of PI.
190 * @return <code>ProcessingInstruction</code> - this PI modified.
191 */
192 public ProcessingInstruction setData(String data) {
193 String reason = Verifier.checkProcessingInstructionData(data);
194 if (reason != null) {
195 throw new IllegalDataException(data, reason);
196 }
197
198 this.rawData = data;
199 this.mapData = parseData(data);
200 return this;
201 }
202
203 /**
204 * This will set the name/value pairs within the passed
205 * <code>Map</code> as the pairs for the data of
206 * this PI. The keys should be the pair name
207 * and the values should be the pair values.
208 *
209 * @param data new map data to use
210 * @return <code>ProcessingInstruction</code> - modified PI.
211 */
212 public ProcessingInstruction setData(Map data) {
213 String temp = toString(data);
214
215 String reason = Verifier.checkProcessingInstructionData(temp);
216 if (reason != null) {
217 throw new IllegalDataException(temp, reason);
218 }
219
220 this.rawData = temp;
221 this.mapData = data;
222 return this;
223 }
224
225
226 /**
227 * This will return the value for a specific
228 * name/value pair on the PI. If no such pair is
229 * found for this PI, null is returned.
230 *
231 * @param name <code>String</code> name of name/value pair
232 * to lookup value for.
233 * @return <code>String</code> - value of name/value pair.
234 */
235 public String getPseudoAttributeValue(String name) {
236 return (String)mapData.get(name);
237 }
238
239 /**
240 * This will set a pseudo attribute with the given name and value.
241 * If the PI data is not already in a pseudo-attribute format, this will
242 * replace the existing data.
243 *
244 * @param name <code>String</code> name of pair.
245 * @param value <code>String</code> value for pair.
246 * @return <code>ProcessingInstruction</code> this PI modified.
247 */
248 public ProcessingInstruction setPseudoAttribute(String name, String value) {
249 String reason = Verifier.checkProcessingInstructionData(name);
250 if (reason != null) {
251 throw new IllegalDataException(name, reason);
252 }
253
254 reason = Verifier.checkProcessingInstructionData(value);
255 if (reason != null) {
256 throw new IllegalDataException(value, reason);
257 }
258
259 this.mapData.put(name, value);
260 this.rawData = toString(mapData);
261 return this;
262 }
263
264
265 /**
266 * This will remove the pseudo attribute with the specified name.
267 *
268 * @param name name of pseudo attribute to remove
269 * @return <code>boolean</code> - whether the requested
270 * instruction was removed.
271 */
272 public boolean removePseudoAttribute(String name) {
273 if ((mapData.remove(name)) != null) {
274 rawData = toString(mapData);
275 return true;
276 }
277
278 return false;
279 }
280
281 /**
282 * This will convert the Map to a string representation.
283 *
284 * @param mapData <code>Map</code> PI data to convert
285 * @return a string representation of the Map as appropriate for a PI
286 */
287 private String toString(Map mapData) {
288 StringBuffer rawData = new StringBuffer();
289
290 Iterator i = mapData.keySet().iterator();
291 while (i.hasNext()) {
292 String name = (String)i.next();
293 String value = (String)mapData.get(name);
294 rawData.append(name)
295 .append("=\"")
296 .append(value)
297 .append("\" ");
298 }
299 // Remove last space, if we did any appending
300 if (rawData.length() > 0) {
301 rawData.setLength(rawData.length() - 1);
302 }
303
304 return rawData.toString();
305 }
306
307 /**
308 * This will parse and load the instructions for the PI.
309 * This is separated to allow it to occur once and then be reused.
310 */
311 private Map parseData(String rawData) {
312 // The parsing here is done largely "by hand" which means the code
313 // gets a little tricky/messy. The following conditions should
314 // now be handled correctly:
315 // <?pi href="http://hi/a=b"?> Reads OK
316 // <?pi href = 'http://hi/a=b' ?> Reads OK
317 // <?pi href\t = \t'http://hi/a=b'?> Reads OK
318 // <?pi href = "http://hi/a=b"?> Reads OK
319 // <?pi?> Empty Map
320 // <?pi id=22?> Empty Map
321 // <?pi id='22?> Empty Map
322
323 Map data = new HashMap();
324
325 // System.out.println("rawData: " + rawData);
326
327 // The inputData variable holds the part of rawData left to parse
328 String inputData = rawData.trim();
329
330 // Iterate through the remaining inputData string
331 while (!inputData.trim().equals("")) {
332 //System.out.println("parseData() looking at: " + inputData);
333
334 // Search for "name =", "name=" or "name1 name2..."
335 String name = "";
336 String value = "";
337 int startName = 0;
338 char previousChar = inputData.charAt(startName);
339 int pos = 1;
340 for (; pos<inputData.length(); pos++) {
341 char currentChar = inputData.charAt(pos);
342 if (currentChar == '=') {
343 name = inputData.substring(startName, pos).trim();
344 // Get the boundaries on the quoted string
345 // We use boundaries so we know where to start next
346 int[] bounds = extractQuotedString(
347 inputData.substring(pos+1));
348 // A null value means a parse error and we return empty!
349 if (bounds == null) {
350 return new HashMap();
351 }
352 value = inputData.substring(bounds[0]+pos+1,
353 bounds[1]+pos+1);
354 pos += bounds[1] + 1; // skip past value
355 break;
356 }
357 else if (Character.isWhitespace(previousChar)
358 && !Character.isWhitespace(currentChar)) {
359 startName = pos;
360 }
361
362 previousChar = currentChar;
363 }
364
365 // Remove the first pos characters; they have been processed
366 inputData = inputData.substring(pos);
367
368 // System.out.println("Extracted (name, value) pair: ("
369 // + name + ", '" + value+"')");
370
371 // If both a name and a value have been found, then add
372 // them to the data Map
373 if (name.length() > 0 && value != null) {
374 //if (data.containsKey(name)) {
375 // A repeat, that's a parse error, so return a null map
376 //return new HashMap();
377 //}
378 //else {
379 data.put(name, value);
380 //}
381 }
382 }
383
384 return data;
385 }
386
387 /**
388 * This is a helper routine, only used by parseData, to extract a
389 * quoted String from the input parameter, rawData. A quoted string
390 * can use either single or double quotes, but they must match up.
391 * A singly quoted string can contain an unbalanced amount of double
392 * quotes, or vice versa. For example, the String "JDOM's the best"
393 * is legal as is 'JDOM"s the best'.
394 *
395 * @param rawData the input string from which a quoted string is to
396 * be extracted.
397 * @return the first quoted string encountered in the input data. If
398 * no quoted string is found, then the empty string, "", is
399 * returned.
400 * @see #parseData
401 */
402 private static int[] extractQuotedString(String rawData) {
403 // Remembers whether we're actually in a quoted string yet
404 boolean inQuotes = false;
405
406 // Remembers which type of quoted string we're in
407 char quoteChar = '"';
408
409 // Stores the position of the first character inside
410 // the quoted string (i.e. the start of the return string)
411 int start = 0;
412
413 // Iterate through the input string looking for the start
414 // and end of the quoted string
415 for (int pos=0; pos < rawData.length(); pos++) {
416 char currentChar = rawData.charAt(pos);
417 if (currentChar=='"' || currentChar=='\'') {
418 if (!inQuotes) {
419 // We're entering a quoted string
420 quoteChar = currentChar;
421 inQuotes = true;
422 start = pos+1;
423 }
424 else if (quoteChar == currentChar) {
425 // We're leaving a quoted string
426 inQuotes = false;
427 return new int[] { start, pos };
428 }
429 // Otherwise we've encountered a quote
430 // inside a quote, so just continue
431 }
432 }
433
434 return null;
435 }
436
437 /**
438 * This returns a <code>String</code> representation of the
439 * <code>ProcessingInstruction</code>, suitable for debugging. If the XML
440 * representation of the <code>ProcessingInstruction</code> is desired,
441 * {@link org.jdom.output.XMLOutputter#outputString(ProcessingInstruction)}
442 * should be used.
443 *
444 * @return <code>String</code> - information about the
445 * <code>ProcessingInstruction</code>
446 */
447 public String toString() {
448 return new StringBuffer()
449 .append("[ProcessingInstruction: ")
450 .append(new org.jdom.output.XMLOutputter().outputString(this))
451 .append("]")
452 .toString();
453 }
454
455 /**
456 * This will return a clone of this <code>ProcessingInstruction</code>.
457 *
458 * @return <code>Object</code> - clone of this
459 * <code>ProcessingInstruction</code>.
460 */
461 public Object clone() {
462 ProcessingInstruction pi = (ProcessingInstruction) super.clone();
463
464 // target and rawdata are immutable and references copied by
465 // Object.clone()
466
467 // Create a new Map object for the clone (since Map isn't Cloneable)
468 if (mapData != null) {
469 pi.mapData = parseData(rawData);
470 }
471 return pi;
472 }
473 }