/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.io.codelist.xml.reader; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.common.codelist.CodeList; /** * Reads an XML based code list * * @author Simon Templer * @partner 01 / Fraunhofer Institute for Computer Graphics Research */ public class XmlCodeList implements CodeList { private static final ALogger log = ALoggerFactory.getLogger(XmlCodeList.class); private static final DocumentBuilderFactory builderFactory = DocumentBuilderFactory .newInstance(); private static final XPathFactory xpathFactory = XPathFactory.newInstance(); private static final String DEF_NS = "http://www.opengis.net/gml"; //$NON-NLS-1$ private final String identifier; private String namespace; private String description; private final URI location; private final Map<String, CodeEntry> entriesByName = new LinkedHashMap<String, CodeEntry>(); private final Map<String, CodeEntry> entriesByIdentifier = new LinkedHashMap<String, CodeEntry>(); /** * Create a code list from an XML document * * @param in the input stream of the XML document * @param location the code list location * @throws Exception if creating the code list fails */ public XmlCodeList(InputStream in, URI location) throws Exception { this.location = location; try { DocumentBuilder builder = builderFactory.newDocumentBuilder(); // don't resolve DTDs - else loading the document might fail without // internet connection builder.setEntityResolver(new EntityResolver() { @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { return new InputSource(new StringReader("")); //$NON-NLS-1$ } }); Document doc = builder.parse(in); XPath xpath = xpathFactory.newXPath(); String id = null; // determine identifier try { Node identifier = ((NodeList) xpath.evaluate( "Dictionary/identifier", doc, XPathConstants.NODESET)).item(0); //$NON-NLS-1$ this.namespace = identifier.getAttributes() .getNamedItem("codeSpace").getTextContent(); //$NON-NLS-1$ id = identifier.getTextContent(); } catch (Throwable e) { // ignore } if (id == null) { try { Node identifier = ((NodeList) xpath.evaluate( "Dictionary/name", doc, XPathConstants.NODESET)).item(0); //$NON-NLS-1$ id = identifier.getTextContent(); } catch (Throwable e) { // ignore } } if (id == null) { id = location.getPath(); int idx = id.lastIndexOf("/"); //$NON-NLS-1$ if (idx >= 0 && idx + 1 < id.length()) { id = id.substring(idx + 1); } } this.identifier = id; // determine description try { Node description = ((NodeList) xpath.evaluate( "Dictionary/description", doc, XPathConstants.NODESET)).item(0); //$NON-NLS-1$ this.description = description.getTextContent(); } catch (Throwable e) { // is optional this.description = null; } // determine entries NodeList entries = (NodeList) xpath.evaluate( "Dictionary/dictionaryEntry/Definition", doc, XPathConstants.NODESET); //$NON-NLS-1$ addEntries(entries); if (this.namespace == null) { // use default namespace this.namespace = DEF_NS; } } catch (Exception e) { log.error("Error determinating type name(s)", e); //$NON-NLS-1$ throw e; } } private void addEntries(NodeList entries) { for (int i = 0; i < entries.getLength(); i++) { Node node = entries.item(i); NodeList children = node.getChildNodes(); String description = null; String identifier = null; String namespace = null; String name = null; for (int j = 0; j < children.getLength(); j++) { Node child = children.item(j); if (child.getNodeName().endsWith("description")) { //$NON-NLS-1$ description = child.getTextContent(); } else if (child.getNodeName().endsWith("identifier") || //$NON-NLS-1$ (child.getNodeName().endsWith("name") && child.getAttributes().getNamedItem("codeSpace") != null)) { //$NON-NLS-1$ //$NON-NLS-2$ identifier = child.getTextContent(); try { namespace = child.getAttributes() .getNamedItem("codeSpace").getTextContent(); //$NON-NLS-1$ } catch (Exception e) { // optional } } else if (child.getNodeName().endsWith("name")) { //$NON-NLS-1$ name = child.getTextContent(); } } if (this.namespace == null) { if (namespace == null) { // use a default namespace this.namespace = DEF_NS; } else { this.namespace = namespace; } } if (namespace == null) { namespace = this.namespace; } if (name != null && identifier != null) { CodeEntry entry = new CodeEntry(name, description, identifier, namespace); this.entriesByName.put(name, entry); this.entriesByIdentifier.put(identifier, entry); } } } /** * @see CodeList#getEntries() */ @Override public Collection<CodeEntry> getEntries() { return new ArrayList<CodeEntry>(entriesByIdentifier.values()); } /** * @see CodeList#getDescription() */ @Override public String getDescription() { return description; } /** * @see CodeList#getIdentifier() */ @Override public String getIdentifier() { return identifier; } /** * @see CodeList#getNamespace() */ @Override public String getNamespace() { return namespace; } /** * @see CodeList#getEntryByName(String) */ @Override public CodeEntry getEntryByName(String name) { return entriesByName.get(name); } /** * @see CodeList#getEntryByIdentifier(String) */ @Override public CodeEntry getEntryByIdentifier(String identifier) { return entriesByIdentifier.get(identifier); } /** * @see CodeList#getLocation() */ @Override public URI getLocation() { return location; } /** * @see Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); result = prime * result + ((location == null) ? 0 : location.hashCode()); result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); return result; } /** * @see Object#equals(Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; XmlCodeList other = (XmlCodeList) obj; if (identifier == null) { if (other.identifier != null) return false; } else if (!identifier.equals(other.identifier)) return false; if (location == null) { if (other.location != null) return false; } else if (!location.equals(other.location)) return false; if (namespace == null) { if (other.namespace != null) return false; } else if (!namespace.equals(other.namespace)) return false; return true; } }