View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  package com.eviware.soapui.support.xml;
13  
14  import java.io.IOException;
15  import java.io.LineNumberReader;
16  import java.io.StringReader;
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import com.eviware.soapui.support.types.StringToStringMap;
24  
25  /***
26   * 
27   * @author lars
28   */
29  public class XPathData
30  {
31  	private StringToStringMap nsMap = new StringToStringMap();
32  	private List<String> pathComponents = new ArrayList<String>();
33  	private String function;
34  	private boolean absolute = false;
35  
36  	public XPathData( StringToStringMap nsMap, List<String> pathComponents, boolean absolute )
37  	{
38  		this.nsMap = nsMap;
39  		this.pathComponents = pathComponents;
40  		this.absolute = absolute;
41  	}
42  
43  	public XPathData( String xpath, boolean skipFirst )
44  	{
45  		try
46  		{
47  			LineNumberReader reader = new LineNumberReader( new StringReader( xpath.trim() ) );
48  			String s;
49  			while( ( s = reader.readLine() ) != null )
50  			{
51  				if( s.startsWith( "declare namespace " ) )
52  				{
53  					String[] words = s.substring( "declare namespace ".length() ).split( "=" );
54  					String prefix = words[0];
55  					int ix1 = words[1].indexOf( '\'' );
56  					int ix2 = words[1].lastIndexOf( '\'' );
57  					String ns = words[1].substring( ix1 + 1, ix2 - ix1 );
58  					nsMap.put( ns, prefix );
59  				}
60  				else
61  				{
62  					if( s.startsWith( "count(" ) && s.endsWith( ")" ) )
63  					{
64  						function = "count";
65  						s = s.substring( "count(".length(), s.length() - ")".length() );
66  					}
67  					else if( s.startsWith( "exists(" ) && s.endsWith( ")" ) )
68  					{
69  						function = "exists";
70  						s = s.substring( "exists(".length(), s.length() - ")".length() );
71  					}
72  
73  					String[] words = s.split( "/" );
74  					int firstWord = 1 + ( skipFirst ? 1 : 0 );
75  					for( int i = firstWord; i < words.length; i++ )
76  					{
77  						pathComponents.add( 0, words[i] );
78  					}
79  				}
80  			}
81  		}
82  		catch( IOException e )
83  		{
84  			throw new RuntimeException( e );
85  		}
86  	}
87  
88  	public void strip()
89  	{
90  		if( pathComponents.size() > 0 && "text()".equals( pathComponents.get( 0 ) ) )
91  			pathComponents.remove( 0 );
92  
93  		for( int i1 = 0; i1 < pathComponents.size(); i1++ )
94  		{
95  			String s = pathComponents.get( i1 );
96  			if( s.indexOf( '[' ) >= 0 )
97  			{
98  				StringBuffer buf = new StringBuffer();
99  				boolean skip = false;
100 				for( int i2 = 0; i2 < s.length(); i2++ )
101 				{
102 					char ch = s.charAt( i2 );
103 					if( ch == '[' )
104 						skip = true;
105 					if( !skip )
106 						buf.append( ch );
107 
108 					if( ch == ']' )
109 						skip = false;
110 				}
111 
112 				s = buf.toString();
113 				pathComponents.set( i1, s );
114 			}
115 		}
116 
117 		function = null;
118 	}
119 
120 	public XPathData createParent()
121 	{
122 		if( pathComponents.isEmpty() )
123 			return null;
124 
125 		StringToStringMap nsMap2 = new StringToStringMap( nsMap );
126 		ArrayList<String> pathComponents2 = new ArrayList<String>( pathComponents );
127 		pathComponents2.remove( 0 );
128 		return new XPathData( nsMap2, pathComponents2, absolute );
129 	}
130 
131 	@Override
132 	public String toString()
133 	{
134 		return getShortPath();
135 	}
136 
137 	@Override
138 	public boolean equals( Object obj )
139 	{
140 		if( obj.getClass() != XPathData.class )
141 			return false;
142 
143 		XPathData other = ( XPathData )obj;
144 		return this.getHashKey().equals( other.getHashKey() );
145 	}
146 
147 	@Override
148 	public int hashCode()
149 	{
150 		return getHashKey().hashCode();
151 	}
152 
153 	public String getHashKey()
154 	{
155 		return getCanonicalPath();
156 	}
157 
158 	public StringToStringMap getNamespaceMap()
159 	{
160 		return nsMap;
161 	}
162 
163 	public List<String> getPathComponents()
164 	{
165 		return pathComponents;
166 	}
167 
168 	public boolean isAttribute()
169 	{
170 		if( pathComponents.isEmpty() )
171 			return false;
172 
173 		String c = pathComponents.get( 0 );
174 		return c.startsWith( "@" );
175 	}
176 
177 	public String getAttributeName()
178 	{
179 		String c = pathComponents.get( 0 );
180 		return c.substring( 1 );
181 	}
182 
183 	public String getFunction()
184 	{
185 		return function;
186 	}
187 
188 	public String getXPath()
189 	{
190 		return buildXPath( null );
191 	}
192 
193 	public String getFullPath()
194 	{
195 		return buildXPath( null );
196 	}
197 
198 	public String buildXPath( XPathModifier modifier )
199 	{
200 		StringBuffer xpath = new StringBuffer();
201 
202 		for( Iterator<String> i = nsMap.keySet().iterator(); i.hasNext(); )
203 		{
204 			String ns = i.next();
205 			xpath.append( "declare namespace " + nsMap.get( ns ) + "='" + ns + "';\n" );
206 		}
207 
208 		if( function != null )
209 			xpath.append( function ).append( "(" );
210 
211 		if( modifier != null )
212 			modifier.beforeSelector( xpath );
213 
214 		String firstComponent = "";
215 		if( pathComponents.size() > 0 )
216 			firstComponent = pathComponents.get( pathComponents.size() - 1 );
217 		if( !absolute && !"".equals( firstComponent ) )
218 			xpath.append( "/" );
219 
220 		for( int c = pathComponents.size() - 1; c >= 0; c-- )
221 		{
222 			xpath.append( "/" ).append( pathComponents.get( c ) );
223 		}
224 
225 		if( modifier != null )
226 			modifier.afterSelector( xpath );
227 
228 		if( function != null )
229 			xpath.append( ")" );
230 
231 		return xpath.toString();
232 	}
233 
234 	public String getPath()
235 	{
236 		StringBuffer buf = new StringBuffer();
237 		buf.append( "/" );
238 
239 		for( int c = pathComponents.size() - 1; c >= 0; c-- )
240 		{
241 			buf.append( "/" ).append( pathComponents.get( c ) );
242 		}
243 
244 		return buf.toString();
245 	}
246 
247 	/*** Get a path with all namespaces replaced. */
248 	public String getCanonicalPath()
249 	{
250 		HashMap<String, String> inverseNsMap = new HashMap<String, String>();
251 		for( String key : nsMap.keySet() )
252 		{
253 			String value = nsMap.get( key );
254 			inverseNsMap.put( value, key );
255 		}
256 
257 		StringBuffer buf = new StringBuffer();
258 		buf.append( "/" );
259 
260 		for( int c = pathComponents.size() - 1; c >= 0; c-- )
261 		{
262 			buf.append( "/" );
263 			String s = pathComponents.get( c );
264 			String[] words = s.split( ":" );
265 			if( words.length == 2 )
266 			{
267 				String ns = inverseNsMap.get( words[0] );
268 				if( ns != null )
269 				{
270 					buf.append( ns ).append( ":" ).append( words[1] );
271 				}
272 				else
273 				{
274 					buf.append( s );
275 				}
276 			}
277 			else
278 			{
279 				buf.append( s );
280 			}
281 		}
282 
283 		return buf.toString();
284 	}
285 
286 	/*** Get a path with no namespaces or namespace prefixes. */
287 	public String getShortPath()
288 	{
289 		StringBuffer buf = new StringBuffer();
290 		buf.append( "/" );
291 
292 		for( int c = pathComponents.size() - 1; c >= 0; c-- )
293 		{
294 			buf.append( "/" );
295 			String s = pathComponents.get( c );
296 			String[] words = s.split( ":" );
297 			if( words.length == 2 )
298 			{
299 				buf.append( words[1] );
300 			}
301 			else
302 			{
303 				buf.append( s );
304 			}
305 		}
306 
307 		return buf.toString();
308 	}
309 
310 	public Collection<String> getNamespaces()
311 	{
312 		return nsMap.keySet();
313 	}
314 
315 	public boolean hasNamespaces()
316 	{
317 		return nsMap != null && !nsMap.isEmpty();
318 	}
319 }