/*- * Copyright © 2009 Diamond Light Source Ltd. * * This file is part of GDA. * * GDA is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License version 3 as published by the Free * Software Foundation. * * GDA is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with GDA. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.gda.util.schema; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * A Class that reads a castor objects schema and provides information * about the elements defined in the xsd. * * There should be a more elegant way of reading the Schema. There is a * Schema object in castor but reading elements appears to involve loops and * visitors which is not what we want. * * For now this class uses xPath. * * @author Matthew Gerring * */ public class SchemaReader { private String nameSpaceURI = "http://www.w3.org/2001/XMLSchema"; private final XPathFactory factory; private final Document doc; /** * Class reads the schema and returns properties contained in it. * Specially set up for Castor schemas in xsd namespace. * @param schemaUrl * @throws Exception */ public SchemaReader(final URL schemaUrl) throws Exception { DocumentBuilderFactory docBuilder = DocumentBuilderFactory.newInstance(); docBuilder.setNamespaceAware(true); // never forget this! DocumentBuilder builder = docBuilder.newDocumentBuilder(); this.doc = builder.parse(schemaUrl.openConnection().getInputStream()); this.factory = XPathFactory.newInstance(); } /** * Gets the legal choices for the element or null if there are none. * @param mainElementName * @param containingElementName * @return List<String> * @throws Exception */ public List<String> getAllowedChoices(final String mainElementName, final String containingElementName) throws Exception { return processExpression("//xsd:schema/xsd:element[@name='"+mainElementName+"']/xsd:complexType/xsd:sequence/xsd:element[@name='"+containingElementName+"']/xsd:simpleType/xsd:restriction/xsd:enumeration", "value"); } /** * * @param parentName * @return list of all elements * @throws Exception */ public List<String> getChildTags(final String parentName) throws Exception { if (parentName == null) { return processExpression("*/xsd:element", "name"); } return processExpression("*//xsd:element[@name='"+parentName+"']/xsd:complexType/xsd:sequence/xsd:element", "name"); } public List<String> getParents(String name) throws Exception { final String expression = "*//xsd:element"; final XPath xpath = factory.newXPath(); xpath.setNamespaceContext(getXSDContext()); final XPathExpression expr = xpath.compile(expression); final Object result = expr.evaluate(doc, XPathConstants.NODESET); if (result==null) return null; final NodeList nodes = (NodeList) result; if (nodes.getLength()<1) return null; final List<String> items = new ArrayList<String>(nodes.getLength()); for (int i = 0; i < nodes.getLength(); i++) { final Node node = nodes.item(i); if (node.getAttributes().getNamedItem("name")!=null && name.equals(node.getAttributes().getNamedItem("name").getNodeValue())) { try { final Node par = node.getParentNode().getParentNode().getParentNode(); if (par.getAttributes().getNamedItem("name")==null) continue; items.add(par.getAttributes().getNamedItem("name").getNodeValue()); } catch (Exception ne) { continue; } } } return items; } private List<String> processExpression(final String expression, final String fieldName) throws Exception{ final XPath xpath = factory.newXPath(); xpath.setNamespaceContext(getXSDContext()); final XPathExpression expr = xpath.compile(expression); final Object result = expr.evaluate(doc, XPathConstants.NODESET); if (result==null) return null; final NodeList nodes = (NodeList) result; if (nodes.getLength()<1) return null; final List<String> items = new ArrayList<String>(nodes.getLength()); for (int i = 0; i < nodes.getLength(); i++) { final Node node = nodes.item(i); items.add(node.getAttributes().getNamedItem(fieldName).getNodeValue()); } return items; } /** * @return the nameSpaceURI */ public String getNameSpaceURI() { return nameSpaceURI; } /** * @param nameSpaceURI the nameSpaceURI to set default http://www.w3.org/2001/XMLSchema */ public void setNameSpaceURI(String nameSpaceURI) { this.nameSpaceURI = nameSpaceURI; } private NamespaceContext getXSDContext() { return new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { if ("xsd".equals(prefix)) { return nameSpaceURI; } return null; } @Override public String getPrefix(String namespaceURI) { // TODO Auto-generated method stub return null; } @SuppressWarnings("rawtypes") @Override public Iterator getPrefixes(String namespaceURI) { // TODO Auto-generated method stub return null; } }; } }