001/* 
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.  
018 */
019
020package org.apache.wiki.util;
021
022import org.apache.commons.lang.StringUtils;
023import org.apache.log4j.Logger;
024import org.jdom2.Document;
025import org.jdom2.Element;
026import org.jdom2.JDOMException;
027import org.jdom2.filter.Filters;
028import org.jdom2.input.SAXBuilder;
029import org.jdom2.xpath.XPathExpression;
030import org.jdom2.xpath.XPathFactory;
031
032import java.io.IOException;
033import java.io.InputStream;
034import java.net.URL;
035import java.util.ArrayList;
036import java.util.Collections;
037import java.util.Enumeration;
038import java.util.HashSet;
039import java.util.List;
040import java.util.Set;
041
042/**
043 *  Utility class to parse XML files.
044 *  <p>
045 *  This uses JDOM2 as its backing implementation.
046 *  </p>
047 *  
048 * @since 2.10
049 */
050public final class XmlUtil
051{   
052    private static final Logger log = Logger.getLogger( XmlUtil.class );
053    
054    private XmlUtil() {}
055    
056    /**
057     * Parses the given XML file and returns the requested nodes. If there's an error accessing or parsing the file, an
058     * empty list is returned.
059     * 
060     * @param xml file to parse; matches all resources from classpath, filters repeated items.
061     * @param requestedNodes requestd nodes on the xml file
062     * @return the requested nodes of the XML file.
063     */
064    public static List<Element> parse( String xml, String requestedNodes )
065    {
066        if( StringUtils.isNotEmpty( xml ) && StringUtils.isNotEmpty( requestedNodes ) ) {
067            Set<Element> readed = new HashSet<Element>();
068            SAXBuilder builder = new SAXBuilder();
069            try {
070                Enumeration< URL > resources = XmlUtil.class.getClassLoader().getResources( xml );
071                while( resources.hasMoreElements() ) {
072                    URL resource = resources.nextElement();
073                    log.debug( "reading " + resource.toString() );
074                    Document doc = builder.build( resource );
075                    XPathFactory xpfac = XPathFactory.instance();
076                    XPathExpression<Element> xp = xpfac.compile( requestedNodes, Filters.element() );
077                    readed.addAll( xp.evaluate( doc ) ); // filter out repeated items
078                }
079                return new ArrayList<Element>( readed );
080            } catch ( IOException ioe ) {
081                log.error( "Couldn't load all " + xml + " resources", ioe );
082            } catch ( JDOMException jdome ) {
083                log.error( "error parsing " + xml + " resources", jdome );
084            }
085        }
086        return Collections.<Element>emptyList();
087    }
088    
089    
090    /**
091     * Parses the given stream and returns the requested nodes. If there's an error accessing or parsing the stream, an
092     * empty list is returned.
093     * 
094     * @param xmlStream stream to parse.
095     * @param requestedNodes requestd nodes on the xml stream.
096     * @return the requested nodes of the XML stream.
097     */
098    public static List<Element> parse( InputStream xmlStream, String requestedNodes )
099    {
100        if( xmlStream != null && StringUtils.isNotEmpty( requestedNodes ) ) {
101            SAXBuilder builder = new SAXBuilder();
102            try {
103                Document doc = builder.build(xmlStream);
104                XPathFactory xpfac = XPathFactory.instance();
105                XPathExpression< Element > xp = xpfac.compile(requestedNodes,Filters.element());
106                return xp.evaluate( doc );
107            } catch ( IOException ioe ) {
108                log.error( "Couldn't load all " + xmlStream + " resources", ioe );
109            } catch ( JDOMException jdome ) {
110                log.error( "error parsing " + xmlStream + " resources", jdome );
111            }
112        }       
113        return Collections.<Element>emptyList();
114    }
115
116}