View Javadoc

1   package org.apache.maven;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import org.xml.sax.Attributes;
25  import org.xml.sax.SAXException;
26  import org.xml.sax.SAXParseException;
27  import org.xml.sax.helpers.XMLFilterImpl;
28  
29  /**
30   * Constructs an XPath expression in the form:
31   *    /root/child[3]/grandchild[2] ...
32   *
33   * @author <a href="mailto:ltheussl@apache.org">Lukas Theussl</a>
34   */
35  public class XPathLocationTracker extends XMLFilterImpl
36  {
37  
38      private State state;
39      private static final Integer[] ints = new Integer[]
40      {
41          new Integer( 0 ),
42          new Integer( 1 ),
43          new Integer( 2 ),
44          new Integer( 3 ),
45          new Integer( 4 )
46      };
47  
48      /**
49       * Overriding ContentHandler.
50       * @throws SAXException SAXException
51       */
52      public void startDocument() throws SAXException
53      {
54          state = new State( null );
55          super.startDocument();
56      }
57  
58      /**
59       * Overriding ContentHandler.
60       * @throws SAXException SAXException
61       */
62      public void endDocument() throws SAXException
63      {
64          super.endDocument();
65          state = null;
66      }
67  
68      /**
69       * Overriding ContentHandler.
70       * @param uri uri
71       * @param localName localName
72       * @param qName qName
73       * @param atts atts
74       * @throws SAXException SAXException
75       */
76      public void startElement( String uri, String localName,
77              String qName, Attributes atts ) throws SAXException
78      {
79          state = state.push( qName );
80          try
81          {
82              super.startElement( uri, localName, qName, atts );
83          }
84          catch ( SAXParseException e )
85          {
86              // ignored on purpose: just avoid to throw an exception here
87              // it is thrown by the ErrorHandler in JaxpMsvBean instead
88          }
89      }
90  
91      /**
92       * Overriding ContentHandler.
93       * @param uri uri
94       * @param localName localName
95       * @param qName qName
96       * @throws SAXException SAXException
97       */
98      public void endElement( String uri, String localName, String qName )
99              throws SAXException
100     {
101         try
102         {
103             super.endElement( uri, localName, qName );
104         }
105         catch ( SAXParseException e )
106         {
107             // ignored on purpose: just avoid to throw an exception here
108             // it is thrown by the ErrorHandler in JaxpMsvBean instead
109         }
110         state = state.pop();
111     }
112 
113     /**
114      * Gets the XPath expression that points to the current location.
115      * Throws a new IllegalStateException if the component is not
116      * parsing a document.
117      * @return The XPath expression
118      */
119     public final String getXPath()
120     {
121         if ( state == null )
122         {
123             throw new IllegalStateException(
124                 "startDocument event is not invoked" );
125         }
126         return state.getXPath();
127     }
128 
129     private static Integer getInt( int i )
130     {
131         if ( i < ints.length )
132         {
133             return ints[i];
134         }
135         else
136         {
137             return new Integer(i);
138         }
139     }
140 
141     private static final class State
142     {
143 
144         private final Map counter = new HashMap();
145         private final State parent;
146         private State child;
147         private String currentName;
148 
149         State( State newParent )
150         {
151             this.parent = newParent;
152         }
153 
154         protected State push( String rawName )
155         {
156             count(rawName);
157             currentName = rawName;
158             if ( child == null )
159             {
160                 child = new State( this );
161             }
162             else
163             {
164                 child.reset();
165             }
166             return child;
167         }
168 
169         protected State pop()
170         {
171             parent.currentName = null;
172             return parent;
173         }
174 
175         private void count( String rawName )
176         {
177             Integer i = (Integer) counter.get( rawName );
178             if ( i == null )
179             {
180                 i = getInt( 1 );
181             }
182             else
183             {
184                 i = getInt( i.intValue() + 1 );
185             }
186             counter.put( rawName, i );
187         }
188 
189         private void reset()
190         {
191             counter.clear();
192             currentName = null;
193         }
194 
195         private String getXPath()
196         {
197             String xPath;
198             if ( parent == null ) // root
199             {
200                 xPath = "/";
201                 if ( currentName != null )
202                 {
203                     xPath += currentName;
204                 }
205             }
206             else // child node
207             {
208                 xPath = parent.getXPath();
209                 if ( currentName != null )
210                 {
211                     xPath += '/' + currentName;
212                     Integer i = (Integer) counter.get( currentName );
213                     xPath += '[' + i.toString() + ']';
214                 }
215             }
216             return xPath;
217         }
218 
219     }
220 
221 }