This project has retired. For details please refer to its Attic page.
XMLReader xref
View Javadoc
1   package org.apache.archiva.xml;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.dom4j.Attribute;
24  import org.dom4j.Document;
25  import org.dom4j.DocumentException;
26  import org.dom4j.Element;
27  import org.dom4j.Namespace;
28  import org.dom4j.Node;
29  import org.dom4j.QName;
30  import org.dom4j.XPath;
31  import org.dom4j.io.SAXReader;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.InputStreamReader;
37  import java.net.MalformedURLException;
38  import java.net.URL;
39  import java.nio.charset.Charset;
40  import java.util.ArrayList;
41  import java.util.HashMap;
42  import java.util.Iterator;
43  import java.util.LinkedHashMap;
44  import java.util.List;
45  import java.util.Map;
46  
47  /**
48   * XMLReader - a set of common xml utility methods for reading content out of an xml file.
49   */
50  public class XMLReader
51  {
52      private URL xmlUrl;
53  
54      private String documentType;
55  
56      private Document document;
57  
58      private Map<String, String> namespaceMap = new HashMap<>();
59  
60      public XMLReader( String type, File file )
61          throws XMLException
62      {
63          if ( !file.exists() )
64          {
65              throw new XMLException( "file does not exist: " + file.getAbsolutePath() );
66          }
67  
68          if ( !file.isFile() )
69          {
70              throw new XMLException( "path is not a file: " + file.getAbsolutePath() );
71          }
72  
73          if ( !file.canRead() )
74          {
75              throw new XMLException( "Cannot read xml file due to permissions: " + file.getAbsolutePath() );
76          }
77  
78          try
79          {
80              init( type, file.toURL() );
81          }
82          catch ( MalformedURLException e )
83          {
84              throw new XMLException( "Unable to translate file " + file + " to URL: " + e.getMessage(), e );
85          }
86      }
87  
88      public XMLReader( String type, URL url )
89          throws XMLException
90      {
91          init( type, url );
92      }
93  
94      private void init( String type, URL url )
95          throws XMLException
96      {
97          this.documentType = type;
98          this.xmlUrl = url;
99  
100         SAXReader reader = new SAXReader();
101 
102         try (InputStream in = url.openStream())
103         {
104             InputStreamReader inReader = new InputStreamReader( in, Charset.forName( "UTF-8" ) );
105             LatinEntityResolutionReader latinReader = new LatinEntityResolutionReader( inReader );
106             this.document = reader.read( latinReader );
107         }
108         catch ( DocumentException e )
109         {
110             throw new XMLException( "Unable to parse " + documentType + " xml " + xmlUrl + ": " + e.getMessage(), e );
111         }
112         catch ( IOException e )
113         {
114             throw new XMLException( "Unable to open stream to " + url + ": " + e.getMessage(), e );
115         }
116 
117         Element root = this.document.getRootElement();
118         if ( root == null )
119         {
120             throw new XMLException( "Invalid " + documentType + " xml: root element is null." );
121         }
122 
123         if ( !StringUtils.equals( root.getName(), documentType ) )
124         {
125             throw new XMLException(
126                 "Invalid " + documentType + " xml: Unexpected root element <" + root.getName() + ">, expected <"
127                     + documentType + ">" );
128         }
129     }
130 
131     public String getDefaultNamespaceURI()
132     {
133         Namespace namespace = this.document.getRootElement().getNamespace();
134         return namespace.getURI();
135     }
136 
137     public void addNamespaceMapping( String elementName, String uri )
138     {
139         this.namespaceMap.put( elementName, uri );
140     }
141 
142     public Element getElement( String xpathExpr )
143         throws XMLException
144     {
145         XPath xpath = createXPath( xpathExpr );
146         Object evaluated = xpath.selectSingleNode( document );
147 
148         if ( evaluated == null )
149         {
150             return null;
151         }
152 
153         if ( evaluated instanceof Element )
154         {
155             return (Element) evaluated;
156         }
157         else
158         {
159             // Unknown evaluated type.
160             throw new XMLException( ".getElement( Expr: " + xpathExpr + " ) resulted in non-Element type -> ("
161                                         + evaluated.getClass().getName() + ") " + evaluated );
162         }
163     }
164 
165     private XPath createXPath( String xpathExpr )
166     {
167         XPath xpath = document.createXPath( xpathExpr );
168         if ( !this.namespaceMap.isEmpty() )
169         {
170             xpath.setNamespaceURIs( this.namespaceMap );
171         }
172         return xpath;
173     }
174 
175     public boolean hasElement( String xpathExpr )
176         throws XMLException
177     {
178         XPath xpath = createXPath( xpathExpr );
179         Object evaluated = xpath.selectSingleNode( document );
180 
181         if ( evaluated == null )
182         {
183             return false;
184         }
185 
186         return true;
187     }
188 
189     /**
190      * Remove namespaces from entire document.
191      */
192     public void removeNamespaces()
193     {
194         removeNamespaces( this.document.getRootElement() );
195     }
196 
197     /**
198      * Remove namespaces from element recursively.
199      */
200     @SuppressWarnings("unchecked")
201     public void removeNamespaces( Element elem )
202     {
203         elem.setQName( QName.get( elem.getName(), Namespace.NO_NAMESPACE, elem.getQualifiedName() ) );
204 
205         Element e;
206         Iterator<Element> elementIterator = elem.elementIterator();
207         while ( elementIterator.hasNext() )
208         {
209             e = elementIterator.next();
210             removeNamespaces(e);
211         }
212 
213         Attribute attribute;
214         Iterator<Attribute> attributeIterator = elem.attributeIterator();
215         LinkedHashMap<String, String> newAttributes = new LinkedHashMap<>();
216         while ( attributeIterator.hasNext() )
217         {
218             attribute = attributeIterator.next();
219             newAttributes.put(attribute.getName(), attribute.getValue());
220         }
221         elem.setAttributes(new ArrayList<Attribute>());
222         for (Map.Entry<String, String> entry : newAttributes.entrySet()) {
223             elem.addAttribute(entry.getKey(), entry.getValue());
224         }
225     }
226 
227     public String getElementText( Node context, String xpathExpr )
228         throws XMLException
229     {
230         XPath xpath = createXPath( xpathExpr );
231         Object evaluated = xpath.selectSingleNode( context );
232 
233         if ( evaluated == null )
234         {
235             return null;
236         }
237 
238         if ( evaluated instanceof Element )
239         {
240             Element evalElem = (Element) evaluated;
241             return evalElem.getTextTrim();
242         }
243         else
244         {
245             // Unknown evaluated type.
246             throw new XMLException( ".getElementText( Node, Expr: " + xpathExpr + " ) resulted in non-Element type -> ("
247                                         + evaluated.getClass().getName() + ") " + evaluated );
248         }
249     }
250 
251     public String getElementText( String xpathExpr )
252         throws XMLException
253     {
254         XPath xpath = createXPath( xpathExpr );
255         Object evaluated = xpath.selectSingleNode( document );
256 
257         if ( evaluated == null )
258         {
259             return null;
260         }
261 
262         if ( evaluated instanceof Element )
263         {
264             Element evalElem = (Element) evaluated;
265             return evalElem.getTextTrim();
266         }
267         else
268         {
269             // Unknown evaluated type.
270             throw new XMLException( ".getElementText( Expr: " + xpathExpr + " ) resulted in non-Element type -> ("
271                                         + evaluated.getClass().getName() + ") " + evaluated );
272         }
273     }
274 
275     @SuppressWarnings("unchecked")
276     public List<Element> getElementList( String xpathExpr )
277         throws XMLException
278     {
279         XPath xpath = createXPath( xpathExpr );
280         Object evaluated = xpath.evaluate( document );
281 
282         if ( evaluated == null )
283         {
284             return null;
285         }
286 
287         /* The xpath.evaluate(Context) method can return:
288          *   1) A Collection or List of dom4j Nodes. 
289          *   2) A single dom4j Node.
290          */
291 
292         if ( evaluated instanceof List )
293         {
294             return (List<Element>) evaluated;
295         }
296         else if ( evaluated instanceof Node )
297         {
298             List<Element> ret = new ArrayList<>();
299             ret.add( (Element) evaluated );
300             return ret;
301         }
302         else
303         {
304             // Unknown evaluated type.
305             throw new XMLException( ".getElementList( Expr: " + xpathExpr + " ) resulted in non-List type -> ("
306                                         + evaluated.getClass().getName() + ") " + evaluated );
307         }
308     }
309 
310     public List<String> getElementListText( String xpathExpr )
311         throws XMLException
312     {
313         List<Element> elemList = getElementList( xpathExpr );
314         if ( elemList == null )
315         {
316             return null;
317         }
318 
319         List<String> ret = new ArrayList<>();
320         for ( Iterator<Element> iter = elemList.iterator(); iter.hasNext(); )
321         {
322             Element listelem = iter.next();
323             ret.add( listelem.getTextTrim() );
324         }
325         return ret;
326     }
327 
328 }