This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.xml;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.commons.lang.StringUtils;
023import org.dom4j.Attribute;
024import org.dom4j.Document;
025import org.dom4j.DocumentException;
026import org.dom4j.Element;
027import org.dom4j.Namespace;
028import org.dom4j.Node;
029import org.dom4j.QName;
030import org.dom4j.XPath;
031import org.dom4j.io.SAXReader;
032
033import java.io.File;
034import java.io.IOException;
035import java.io.InputStream;
036import java.io.InputStreamReader;
037import java.net.MalformedURLException;
038import java.net.URL;
039import java.nio.charset.Charset;
040import java.util.ArrayList;
041import java.util.HashMap;
042import java.util.Iterator;
043import java.util.LinkedHashMap;
044import java.util.List;
045import java.util.Map;
046
047/**
048 * XMLReader - a set of common xml utility methods for reading content out of an xml file.
049 */
050public class XMLReader
051{
052    private URL xmlUrl;
053
054    private String documentType;
055
056    private Document document;
057
058    private Map<String, String> namespaceMap = new HashMap<>();
059
060    public XMLReader( String type, File file )
061        throws XMLException
062    {
063        if ( !file.exists() )
064        {
065            throw new XMLException( "file does not exist: " + file.getAbsolutePath() );
066        }
067
068        if ( !file.isFile() )
069        {
070            throw new XMLException( "path is not a file: " + file.getAbsolutePath() );
071        }
072
073        if ( !file.canRead() )
074        {
075            throw new XMLException( "Cannot read xml file due to permissions: " + file.getAbsolutePath() );
076        }
077
078        try
079        {
080            init( type, file.toURL() );
081        }
082        catch ( MalformedURLException e )
083        {
084            throw new XMLException( "Unable to translate file " + file + " to URL: " + e.getMessage(), e );
085        }
086    }
087
088    public XMLReader( String type, URL url )
089        throws XMLException
090    {
091        init( type, url );
092    }
093
094    private void init( String type, URL url )
095        throws XMLException
096    {
097        this.documentType = type;
098        this.xmlUrl = url;
099
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}