KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > schema2beans > XMLUtil


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.schema2beans;
21
22 import java.io.*;
23 import org.w3c.dom.*;
24 import org.xml.sax.*;
25
26 public class XMLUtil {
27     private XMLUtil() {}
28
29     /**
30      * Takes some text to be printed into an XML stream and escapes any
31      * characters that might make it invalid XML (like '<').
32      */

33     public static void printXML(StringBuffer JavaDoc out, String JavaDoc msg) {
34         printXML(out, msg, true);
35     }
36
37     public static void printXML(StringBuffer JavaDoc out, String JavaDoc msg, boolean attribute) {
38         if (msg == null) return;
39         appendLine(out, msg, attribute);
40     }
41
42     /** @deprecated this public method is not expected to be used by schema2beans client
43      */

44     public static void printXML(StringBuffer JavaDoc out, char msg, boolean attribute) {
45         if (msg == '&')
46             out.append("&amp;");
47         else if (msg == '<')
48             out.append("&lt;");
49         else if (msg == '>')
50             out.append("&gt;");
51         else if (attribute) {
52             if (msg == '"')
53                 out.append("&quot;");
54             else if (msg == '\'')
55                 out.append("&apos;");
56             else if (msg == '\n')
57                 out.append("&#xA");
58             else if (msg == '\t')
59                 out.append("&#x9");
60             else
61                 out.append(msg);
62         } else
63             out.append(msg);
64     }
65     
66     /**
67      * Takes some text to be printed into an XML stream and escapes any
68      * characters that might make it invalid XML (like '<').
69      */

70     public static void writeXML(java.io.Writer JavaDoc out, String JavaDoc msg) throws java.io.IOException JavaDoc {
71         writeXML(out, msg, true);
72     }
73
74     public static void writeXML(java.io.Writer JavaDoc out, String JavaDoc msg, boolean attribute) throws java.io.IOException JavaDoc {
75             if (msg == null) return;
76             appendLine(out,msg,attribute);
77     }
78         
79         /** @deprecated this public method is not expected to be used by schema2beans client
80          */

81     public static void writeXML(java.io.Writer JavaDoc out, char msg, boolean attribute) throws java.io.IOException JavaDoc {
82         if (msg == '&')
83             out.write("&amp;");
84         else if (msg == '<')
85             out.write("&lt;");
86         else if (msg == '>')
87             out.write("&gt;");
88         else if (attribute) {
89             if (msg == '"')
90                 out.write("&quot;");
91             else if (msg == '\'')
92                 out.write("&apos;");
93             else if (msg == '\n')
94                 out.write("&#xA;");
95             else if (msg == '\t')
96                 out.write("&#x9;");
97             else
98                 out.write(msg);
99         } else
100             out.write(msg);
101     }
102
103     public static boolean shouldEscape(char c) {
104         if (c == '&')
105             return true;
106         else if (c == '<')
107             return true;
108         else if (c == '>')
109             return true;
110         return false;
111     }
112
113     public static boolean shouldEscape(String JavaDoc s) {
114         if (s == null)
115             return false;
116         int msgLength = s.length();
117         for (int i = 0; i < msgLength; ++i) {
118             char c = s.charAt(i);
119             if (shouldEscape(c))
120                 return true;
121         }
122         return false;
123     }
124
125     /**
126      * Takes some text to be printed into an XML stream and escapes any
127      * characters that might make it invalid XML (like '<').
128      */

129     public static void printXML(java.io.Writer JavaDoc out, String JavaDoc msg) throws java.io.IOException JavaDoc {
130         printXML(out, msg, true);
131     }
132
133     public static void printXML(java.io.Writer JavaDoc out, String JavaDoc msg, boolean attribute) throws java.io.IOException JavaDoc {
134         if (msg == null) return;
135         appendLine(out,msg,attribute);
136     }
137     
138     private static void appendLine(StringBuffer JavaDoc out, String JavaDoc msg, boolean attribute) {
139         out.append(convertChars(msg,attribute));
140     }
141     
142     private static void appendLine(java.io.Writer JavaDoc out, String JavaDoc msg, boolean attribute) throws java.io.IOException JavaDoc {
143         out.write(convertChars(msg,attribute));
144     }
145
146     private static String JavaDoc convertChars(String JavaDoc msg, boolean attribute) {
147         String JavaDoc result=msg;
148         if (msg.indexOf("&")>=0) //NOI18N
149
result = result.replaceAll("&","&amp;"); //NOI18N
150
if (msg.indexOf("<")>=0) //NOI18N
151
result = result.replaceAll("<","&lt;"); //NOI18N
152
if (msg.indexOf(">")>=0) //NOI18N
153
result = result.replaceAll(">","&gt;"); //NOI18N
154
if (attribute) { //NOI18N
155
if (msg.indexOf("\"")>=0) //NOI18N
156
result = result.replaceAll("\"","&quot;"); //NOI18N
157
if (msg.indexOf("'")>=0) //NOI18N
158
result = result.replaceAll("'","&apos;"); //NOI18N
159
if (msg.indexOf("\n")>=0) //NOI18N
160
result = result.replaceAll("\n","&#xA"); //NOI18N
161
if (msg.indexOf("\t")>=0) //NOI18N
162
result = result.replaceAll("\t","&#x9"); //NOI18N
163
}
164         return result;
165     }
166     
167     /** @deprecated this public method is not expected to be used by schema2beans client
168      */

169     public static void printXML(java.io.Writer JavaDoc out, char msg, boolean attribute) throws java.io.IOException JavaDoc {
170         if (msg == '&')
171             out.write("&amp;");
172         else if (msg == '<')
173             out.write("&lt;");
174         else if (msg == '>')
175             out.write("&gt;");
176         else if (attribute) {
177             if (msg == '"')
178                 out.write("&quot;");
179             else if (msg == '\'')
180                 out.write("&apos;");
181             else if (msg == '\n')
182                 out.write("&#xA;");
183             else if (msg == '\t')
184                 out.write("&#x9;");
185             else
186                 out.write(msg);
187         }
188         else
189             out.write(msg);
190     }
191
192     public static class DOMWriter {
193         private java.io.Writer JavaDoc out;
194         private boolean writeCData = false;
195         private String JavaDoc docTypePublic;
196         private String JavaDoc docTypeSystem;
197         
198         public DOMWriter() {
199         }
200
201         public void setWriter(java.io.Writer JavaDoc out) {
202             this.out = out;
203         }
204         
205         public void setWriteCData(boolean value) {
206             writeCData = value;
207         }
208
209         public void setDocTypePublic(String JavaDoc value) {
210             docTypePublic = value;
211         }
212
213         public void setDocTypeSystem(String JavaDoc value) {
214             docTypeSystem = value;
215         }
216
217         /**
218          * Same as write(OutputStream os, Document document)
219          * where os = the file's OutputStream.
220          */

221         public void write(File f, Document document) throws java.io.IOException JavaDoc {
222             OutputStream fout = new FileOutputStream(f);
223             try {
224                 write(fout, document);
225             } finally {
226                 fout.close();
227             }
228         }
229
230         /**
231          * Same as write(OutputStream os, String encoding, Document document)
232          * where encoding == null.
233          */

234         public void write(OutputStream os, Document document) throws java.io.IOException JavaDoc {
235             write(os, null, document);
236         }
237
238         /**
239          * Create an output Writer based on the OutputStream using the
240          * encoding (use "UTF-8" if encoding == null), then write the DOM
241          * graph out.
242          */

243         public void write(OutputStream os, String JavaDoc encoding, Document document) throws java.io.IOException JavaDoc {
244             if (encoding == null)
245                 encoding = "UTF-8";
246             out = new BufferedWriter(new OutputStreamWriter(os, encoding));
247             write(document, encoding);
248         }
249
250         /**
251          * Assumes that the output Writer has already been set.
252          */

253         public void write(Document document) throws java.io.IOException JavaDoc {
254             write(document, null);
255         }
256         
257         /**
258          * Assumes that the output Writer has already been set.
259          * @param encoding goes into the XML header.
260          */

261         public void write(Document document, String JavaDoc encoding) throws java.io.IOException JavaDoc {
262             write(document, encoding, true);
263         }
264         
265         /**
266          * Assumes that the output Writer has already been set.
267          * @param encoding goes into the XML header.
268          * @param writeHeader whether or not the "<?xml ..." header gets
269          * written out as well.
270          */

271         public void write(Document document, String JavaDoc encoding,
272                           boolean writeHeader) throws java.io.IOException JavaDoc {
273             if (writeHeader) {
274                 out.write("<?xml version=\"1.0\""); // NOI18N
275
if (encoding != null) {
276                     out.write(" encoding=\""+encoding+"\"?>\n"); // NOI18N
277
} else
278                     out.write(" encoding=\"UTF-8\"?>\n"); // NOI18N
279
}
280             if (docTypePublic != null || docTypeSystem != null) {
281                 String JavaDoc docName = getDocTypeName(document);
282                 DocumentType docType = document.getDoctype();
283                 NamedNodeMap entities = null;
284                 if (docType != null)
285                     entities = docType.getEntities();
286                 write(docName, docTypePublic, docTypeSystem, entities);
287                 out.write("\n");
288             }
289             NodeList children = document.getChildNodes();
290             int length = children.getLength();
291             // First print out any DocumentTypes
292
for (int i = 0; i < length; ++i) {
293                 Node node = children.item(i);
294                 if (node instanceof DocumentType) {
295                     write(node);
296                     out.write("\n");
297                 }
298             }
299             // Now print everything, but DocumentTypes
300
for (int i = 0; i < length; ++i) {
301                 Node node = children.item(i);
302                 if (!(node instanceof DocumentType)) {
303                     write(node);
304                     out.write("\n");
305                 }
306             }
307
308             out.flush();
309         }
310     
311        public void write(Node node) throws java.io.IOException JavaDoc {
312             boolean needsReturnBetweenChildren = false;
313
314             NodeList children = node.getChildNodes();
315             if (node instanceof Element) {
316                 out.write("<"+node.getNodeName());
317                 write(node.getAttributes());
318                 if (children.getLength() == 0 ||
319                     (children.getLength() == 1 &&
320                      children.item(0) instanceof Text &&
321                      "".equals(children.item(0).getNodeValue()) )) {
322                     out.write("/>");
323                     return;
324                 }
325                 out.write(">");
326             } else if (node instanceof Text) {
327                 printXML(node.getNodeValue(), false);
328             } else if (node instanceof Document) {
329                 needsReturnBetweenChildren = true;
330             } else if (node instanceof DocumentType) {
331                 write((DocumentType) node);
332             } else if (node instanceof Comment) {
333                 write((Comment) node);
334             } else if (node instanceof Entity) {
335                 write((Entity) node);
336             } else if (node instanceof ProcessingInstruction) {
337                 write((ProcessingInstruction) node);
338             } else {
339                 System.err.println("! schema2beans found unknown node type in DOM graph:");
340                 System.err.println("write: node.getClass="+node.getClass()+" node="+node);
341                 System.err.println("write: nodename="+node.getNodeName()+" nodevalue="+node.getNodeValue());
342                 System.err.println("write: getAttributes="+node.getAttributes());
343             }
344         
345             int length = children.getLength();
346             for (int i = 0; i < length; ++i) {
347                 write(children.item(i));
348                 if (needsReturnBetweenChildren)
349                     out.write("\n");
350             }
351             if (node instanceof Element) {
352                 out.write("</"+node.getNodeName()+">");
353             }
354         }
355
356         protected void write(DocumentType docType) throws java.io.IOException JavaDoc {
357             //System.out.println("! FOUND DOCTYPE for "+docType.getName());
358
if (docTypePublic != null || docTypeSystem != null) {
359                 // The header printing has already taken care of the DOCTYPE.
360
return;
361             }
362             write(docType.getName(), docType.getPublicId(),
363                   docType.getSystemId(), docType.getEntities());
364         }
365
366         protected void write(String JavaDoc docName, String JavaDoc publicId,
367                              String JavaDoc systemId, NamedNodeMap entities) throws java.io.IOException JavaDoc {
368             out.write("<!DOCTYPE "+docName); // NOI18N
369
if (publicId != null) {
370                 out.write(" PUBLIC \""); // NOI18N
371
XMLUtil.printXML(out, publicId);
372                 out.write("\""); // NOI18N
373
if (systemId == null)
374                     systemId = "SYSTEM"; // NOI18N
375
}
376             if (systemId != null) {
377                 out.write(" \""); // NOI18N
378
XMLUtil.printXML(out, systemId);
379                 out.write("\""); // NOI18N
380
}
381             if (entities != null) {
382                 int length = entities.getLength();
383                 if (length > 0) {
384                     out.write(" ["); // NOI18N
385
for (int i = 0; i < length; ++i) {
386                         Node node = entities.item(i);
387                         write(node);
388                     }
389                     out.write("]"); // NOI18N
390
}
391             }
392             out.write(">"); // NOI18N
393
}
394
395         protected void write(Comment comment) throws java.io.IOException JavaDoc {
396             // Does not need to have anything escaped (no printXML).
397
out.write("<!--");
398             String JavaDoc text = comment.getNodeValue();
399             // A comment is not allow to have "--" inside of it.
400
int pos = text.indexOf("--");
401             while (pos >= 0) {
402                 out.write(text.substring(0, pos));
403                 out.write("&#x2d;&#x2d;");
404                 text = text.substring(pos+2, text.length());
405                 pos = text.indexOf("--");
406             }
407             out.write(text);
408             out.write("-->");
409         }
410
411         protected void write(Entity entity) throws java.io.IOException JavaDoc {
412             out.write("<!ENTITY "+entity.getNodeName());
413             /*
414               We don't seem to be able to get any useful info out of the
415               Entity object.
416           
417               out.write(" notation ");
418               if (entity.getNotationName() != null)
419               out.write(entity.getNotationName());
420               out.write(" publicid ");
421               if (entity.getPublicId() != null)
422               out.write(entity.getPublicId());
423               out.write(" systemid ");
424               if (entity.getSystemId() != null)
425               out.write(entity.getSystemId());
426             */

427             out.write(" UNKNOWN>");
428         }
429
430         protected void write(ProcessingInstruction pi) throws java.io.IOException JavaDoc {
431             // Does not need to have anything escaped (no printXML).
432
if ("xml".equals(pi.getTarget())) {
433                 // We've already printed out the standard xml PI, suppress this one.
434
return;
435             }
436             out.write("<?"+pi.getTarget()+" "+pi.getData()+"?>");
437         }
438
439         /**
440          * This is used to print attributes.
441          */

442         protected void write(NamedNodeMap nodes) throws java.io.IOException JavaDoc {
443             int length = nodes.getLength();
444             for (int i = 0; i < length; ++i) {
445                 Node node = nodes.item(i);
446                 out.write(" ");
447                 out.write(node.getNodeName());
448                 out.write("=\"");
449                 XMLUtil.printXML(out, node.getNodeValue());
450                 out.write("\"");
451             }
452         }
453
454         protected void printXML(String JavaDoc msg, boolean attribute) throws java.io.IOException JavaDoc {
455             if (writeCData && msg.indexOf("]]>") < 0) {
456                 boolean shouldEscape = XMLUtil.shouldEscape(msg);
457                 if (shouldEscape)
458                     out.write("<![CDATA[");
459                 out.write(msg);
460                 if (shouldEscape)
461                     out.write("]]>");
462             } else
463                 XMLUtil.printXML(out, msg, attribute);
464         }
465     }
466
467     // Given @param doc what should it's DOCTYPE name be.
468
static protected String JavaDoc getDocTypeName(Document doc) {
469         // First look for a DOCTYPE
470
NodeList children = doc.getChildNodes();
471         int length = children.getLength();
472         for (int i = 0; i < length; ++i) {
473             Node node = children.item(i);
474             if (node instanceof DocumentType) {
475                 DocumentType docType = (DocumentType) node;
476                 return docType.getName();
477             }
478         }
479         // Otherwise, check the first node of the actual document
480
Node rootNode = doc.getDocumentElement();
481         return rootNode.getNodeName();
482     }
483
484     /**
485      * Reformat the DOM graph to make it look like pretty XML.
486      *
487      * @param doc The Document to create new TextNodes from.
488      * @param indent The String used to indent per level
489      */

490     public static void reindent(Document doc, String JavaDoc indent) {
491         reindent(doc, doc, -1, indent);
492     }
493     
494     /**
495      * Reformat the DOM graph to make it look like pretty XML.
496      *
497      * @param doc The Document to create new TextNodes from.
498      * @param node The top of the tree to reindent from.
499      * @param indent The String used to indent per level
500      * @param level How far in to reindent
501      * @return true if node is a Text node that has only whitespace
502      */

503     public static boolean reindent(Document doc, Node node,
504                                    int level, String JavaDoc indent) {
505         String JavaDoc nodeValue = node.getNodeValue();
506
507         boolean hasOnlyWhitespaceTextChildren = true;
508         NodeList children = node.getChildNodes();
509         int length = children.getLength();
510         for (int i = 0; i < length; ++i) {
511             if (!reindent(doc, children.item(i), level+1, indent))
512                 hasOnlyWhitespaceTextChildren = false;
513         }
514
515         /*
516         try {
517             printLevel(System.out, level, indent,
518                        node.getNodeName()+": \""+nodeValue+"\"\n");
519             printLevel(System.out, level, indent,
520                        "hasOnlyWhitespaceTextChildren="+hasOnlyWhitespaceTextChildren+"\n");
521         } catch (java.io.IOException e) {
522             e.printStackTrace();
523         }
524         */

525
526         if (hasOnlyWhitespaceTextChildren && level >= 0 && length > 0) {
527             // We can reindent this one. So, go thru each child node
528
// and make sure it's intendation is where we want it.
529

530             StringBuffer JavaDoc idealWhitespaceBuf = new StringBuffer JavaDoc();
531             printLevel(idealWhitespaceBuf, level, indent);
532             String JavaDoc idealFinalWhitespace = "\n" + idealWhitespaceBuf.toString().intern();
533             printLevel(idealWhitespaceBuf, 1, indent);
534             String JavaDoc idealChildWhitespace = "\n"+idealWhitespaceBuf.toString().intern();
535             //System.out.println("idealChildWhitespace='"+idealChildWhitespace+"'");
536
//
537
// Check to make sure the last child node is a text node.
538
// If not, insert the correct spacing at the end.
539
//
540
if (length > 1 && !(children.item(length-1) instanceof Text)) {
541                 //System.out.println("Inserting additional whitespace at end of child list.");
542
node.appendChild(doc.createTextNode(idealFinalWhitespace));
543                 ++length;
544             }
545             //System.out.println("node.getNodeName="+node.getNodeName()+" children.length="+length);
546

547             boolean shouldBeTextNode = true; // This alternates
548
Text textNode;
549             for (int i = 0; i < length; ++i) {
550                 Node childNode = children.item(i);
551                 boolean isTextNode = (childNode instanceof Text);
552                 //System.out.println("shouldBeTextNode="+shouldBeTextNode+" isTextNode="+isTextNode+" "+childNode.getNodeName());
553
if (shouldBeTextNode) {
554                     if (isTextNode) {
555                         String JavaDoc childNodeValue = childNode.getNodeValue().intern();
556                         if (length == 1) {
557                             // We have a single text child, don't mess with
558
// it's contents.
559
continue;
560                         }
561                         
562                         textNode = (Text) childNode;
563                         // Need to make sure it has the correct whitespace
564
if (i == length-1) {
565                             if (idealFinalWhitespace != childNodeValue) {
566                                 //System.out.println("!Incorrect whitespace on final!");
567
if (textNode.getLength() > 0)
568                                     textNode.deleteData(0, textNode.getLength());
569                                 textNode.appendData(idealFinalWhitespace);
570                             }
571                             
572                         } else {
573                             if (idealChildWhitespace != childNodeValue) {
574                                 //System.out.println("!Incorrect whitespace: '"+childNodeValue+"' versus ideal of '"+idealChildWhitespace+"'");
575
textNode.deleteData(0, textNode.getLength());
576                                 textNode.appendData(idealChildWhitespace);
577                             }
578                         }
579                         shouldBeTextNode ^= true;
580                     } else {
581                         // Need to insert a whitespace node
582
//System.out.println("Need to insert a whitespace node before "+childNode.getNodeName()+": "+childNode.getNodeValue());
583
if (i == length-1) {
584                             //System.out.println("It's a final one!");
585
node.insertBefore(doc.createTextNode(idealChildWhitespace), childNode);
586                             node.appendChild(doc.createTextNode(idealFinalWhitespace));
587                             ++length;
588                         } else {
589                             //System.out.println("Not final.");
590
node.insertBefore(doc.createTextNode(idealChildWhitespace), childNode);
591                         }
592                         //
593
// We updated our list while going thru it at the same
594
// time, so update our indices to account for the
595
// new growth.
596
//
597
++i;
598                         ++length;
599                     }
600                 } else {
601                     if (isTextNode) {
602                         // The last whitespace node is correct, so this one
603
// must be extra.
604
//System.out.println("Extra unneeded whitespace");
605
node.removeChild(childNode);
606                         --i;
607                         --length;
608                         if (i == length-1 && i >= 0) {
609                             //System.out.println("It's a final one!");
610
// Go back and fix up the last node.
611
childNode = children.item(i);
612                             String JavaDoc childNodeValue = childNode.getNodeValue().intern();
613                             if (idealFinalWhitespace != childNodeValue) {
614                                 textNode = (Text) childNode;
615                                 //System.out.println("!Incorrect whitespace on final!");
616
if (textNode.getLength() > 0)
617                                     textNode.deleteData(0, textNode.getLength());
618                                 textNode.appendData(idealFinalWhitespace);
619                             }
620                         }
621                     } else {
622                         // This is just right.
623
//System.out.println("This is just right.");
624
shouldBeTextNode ^= true;
625                     }
626                 }
627             }
628         }
629
630         // Let my caller know if I'm a Text node that has only whitespace
631
// or not.
632
if (node instanceof Text) {
633             if (nodeValue == null)
634                 return true;
635             return (nodeValue.trim().equals(""));
636         }
637         return true;
638     }
639
640     protected static void printLevel(StringBuffer JavaDoc out, int level, String JavaDoc indent) {
641         for (int i = 0; i < level; ++i) {
642             out.append(indent);
643         }
644     }
645
646     /**
647      * Given an XPath expression, find it's location in a Document
648      * @return null if not found
649      */

650     public static Locator findLocationXPath(InputSource in, String JavaDoc xpathExpr) throws IOException, org.xml.sax.SAXException JavaDoc {
651         XMLReader parser;
652         try {
653             javax.xml.parsers.SAXParserFactory JavaDoc spf
654                 = javax.xml.parsers.SAXParserFactory.newInstance();
655             spf.setNamespaceAware(true);
656             parser = spf.newSAXParser().getXMLReader();
657         } catch (javax.xml.parsers.ParserConfigurationException JavaDoc e) {
658             throw new RuntimeException JavaDoc(e);
659         }
660         XPathLocator locator = new XPathLocator(xpathExpr);
661         parser.setContentHandler(locator);
662         parser.parse(in);
663         return locator.getDocumentLocator();
664     }
665     
666     /** Test if character can be in attr value
667      */

668     public static boolean isAttrContent(int i) {
669         // return false for leading ACSII chars (except tab char)
670
if (i<9) return false;
671         if (i>9 && i<32) return false;
672         // return false for <, ]
673
// if (i==60 || i==93) return false;
674
// otherwise return true
675
return true;
676     }
677
678     private static class XPathLocator
679         extends org.xml.sax.helpers.DefaultHandler JavaDoc implements ContentHandler {
680         private String JavaDoc xpathExpr;
681         private String JavaDoc[] xpathParts;
682         private int partNum;
683         private String JavaDoc desiredElementName;
684         private int desiredPosition;
685         private boolean isAttribute;
686         private Locator locator = null;
687         private Locator resultLocator = null;
688
689         public XPathLocator(String JavaDoc xpathExpr) {
690             xpathExpr = xpathExpr.trim();
691             if (xpathExpr.startsWith("/"))
692                 xpathExpr = xpathExpr.substring(1, xpathExpr.length());
693             this.xpathExpr = xpathExpr;
694             xpathParts = xpathExpr.split("/"); // This is a bit too simple.
695
partNum = 0;
696             setElementName();
697         }
698
699         private void setElementName() {
700             desiredElementName = xpathParts[partNum].trim();
701             desiredPosition = 0;
702             isAttribute = false;
703             int startPos = desiredElementName.indexOf('[');
704             int endPos = desiredElementName.indexOf(']');
705             //System.out.println("desiredElementName="+desiredElementName);
706
if (startPos >= 0) {
707                 if (endPos < 0)
708                     throw new IllegalArgumentException JavaDoc("XPath subexpression ("+desiredElementName+") is missing an ending ']'.");
709                 String JavaDoc subExpr = desiredElementName.substring(startPos+1,
710                                                               endPos).trim();
711                 desiredElementName = desiredElementName.substring(0, startPos);
712                 //System.out.println("subExpr="+subExpr);
713
if (subExpr.startsWith("position()=")) {
714                     desiredPosition = Integer.parseInt(subExpr.substring(11, subExpr.length()));
715                 } else {
716                     boolean allDigits = subExpr.length() > 0;
717                     for (int i = 0; i < subExpr.length(); ++i) {
718                         if (!Character.isDigit(subExpr.charAt(i))) {
719                             allDigits = false;
720                             break;
721                         }
722                     }
723                     if (allDigits) {
724                         desiredPosition = Integer.parseInt(subExpr);
725                     } else {
726                         throw new UnsupportedOperationException JavaDoc("XPath ("+subExpr+" in "+xpathExpr+") not supported.");
727                     }
728                 }
729             } else if (desiredElementName.startsWith("@")) {
730                 isAttribute = true;
731                 desiredElementName = desiredElementName.substring(1, desiredElementName.length());
732             }
733             //System.out.println("desiredElementName="+desiredElementName);
734
}
735
736         /**
737          * @return true means done
738          */

739         private boolean foundGotoNext() {
740             ++partNum;
741             if (partNum >= xpathParts.length) {
742                 // Found the final one!
743
resultLocator = new org.xml.sax.helpers.LocatorImpl JavaDoc(locator);
744                 return true;
745             } else {
746                 // goto the next subexpression
747
setElementName();
748                 return false;
749             }
750         }
751
752         public Locator getDocumentLocator() {
753             return resultLocator;
754         }
755         
756         public void setDocumentLocator(Locator locator) {
757             this.locator = locator;
758         }
759
760         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName,
761                                  String JavaDoc rawName, Attributes attrs) throws SAXException {
762             if (resultLocator != null) {
763                 // It's already found.
764
return;
765             }
766             if (desiredElementName.equals(localName) ||
767                 desiredElementName.equals(rawName)) {
768                 //System.out.println("Found "+desiredElementName);
769
if (desiredPosition == 0) {
770                     // Found the one we wanted
771
if (!foundGotoNext()) {
772                         // See if the next one is an attribute, in which case
773
// we need to handle it here.
774
if (isAttribute) {
775                             // Now go find an attribute.
776
for (int i = 0, size = attrs.getLength();
777                                  i < size; ++i) {
778                                 if (desiredElementName.equals(attrs.getLocalName(i)) ||
779                                     desiredElementName.equals(attrs.getQName(i))) {
780                                     // Found our attribute
781
foundGotoNext();
782                                     return;
783                                 }
784                             }
785                         }
786                     }
787                 } else {
788                     --desiredPosition;
789                 }
790             }
791         }
792     }
793 }
794
Popular Tags