/******************************************************************************* * Copyright 2012 Pearson Education * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.semantictools.frame.api.impl; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.semantictools.frame.api.TypeManager; import org.semantictools.frame.model.Datatype; import org.semantictools.frame.model.OntologyInfo; import org.semantictools.frame.model.OntologyType; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import com.hp.hpl.jena.vocabulary.XSD; public class DatatypeReader { private TypeManager typeManager; public DatatypeReader(TypeManager typeManager) { this.typeManager = typeManager; } public void read(InputStream input) throws IOException, ParserConfigurationException, SAXException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.setFeature("http://xml.org/sax/features/namespaces", true); XmlHandler handler = new XmlHandler(); reader.setContentHandler(handler); parser.parse(input, handler); } static enum NumberType { FLOAT, DOUBLE, INT, LONG, SHORT, BYTE, NONE } class XmlHandler extends DefaultHandler { private Map<String, String> namespaceMap = new HashMap<String, String>(); private String targetNamespace; private String shortName; private String typeURI; private String baseURI; private Integer length; private Integer minLength; private Integer maxLength; private String pattern; private Number maxInclusive; private Number minInclusive; private Number maxExclusive; private Number minExclusive; private Integer totalDigits; private Integer fractionDigits; private NumberType numberType = NumberType.NONE; private StringBuilder characters; private OntologyInfo ontInfo; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("schema".equals(localName)) { targetNamespace = toRdfNamespace(attributes.getValue("targetNamespace")); ontInfo = new OntologyInfo(); ontInfo.setOntologyURI(targetNamespace); ontInfo.setNamespaceUri(targetNamespace); ontInfo.setType(OntologyType.XSD); parseNamespaces(attributes); } else if ("simpleType".equals(localName)) { shortName = attributes.getValue("name"); typeURI = toURI(shortName); } else if ("restriction".equals(localName)) { baseURI = toURI(attributes.getValue("base")); setNumberType(); } else if ("length".equals(localName)) { length = Integer.valueOf(attributes.getValue("value")); } else if ("maxExclusive".equals(localName)) { maxExclusive = getNumber(attributes.getValue("value")); } else if ("minExclusive".equals(localName)) { minExclusive = getNumber(attributes.getValue("value")); } else if ("maxInclusive".equals(localName)) { maxInclusive = getNumber(attributes.getValue("value")); } else if ("minInclusive".equals(localName)) { minInclusive = getNumber(attributes.getValue("value")); } else if ("factionDigits".equals(localName)) { fractionDigits = Integer.valueOf(attributes.getValue("value")); } else if ("maxLength".equals(localName)) { maxLength = Integer.valueOf(attributes.getValue("value")); } else if ("minLength".equals(localName)) { minLength = Integer.valueOf(attributes.getValue("value")); } else if ("totalDigits".equals(localName)) { totalDigits = Integer.valueOf(attributes.getValue("value")); } else if ("pattern".equals(localName)) { pattern = attributes.getValue("value"); } else if ("label".equals(localName) || "prefix".equals(localName)) { characters = new StringBuilder(); } } @Override public void characters(char[] ch, int start, int length) { if (characters != null) { characters.append(ch, start, length); } } private void setNumberType() { if ( XSD.decimal.getURI().equals(baseURI) || XSD.xdouble.getURI().equals(baseURI) ) { numberType = NumberType.DOUBLE; } else if (XSD.xfloat.getURI().equals(baseURI)) { numberType = NumberType.FLOAT; } else if ( XSD.integer.getURI().equals(baseURI) || XSD.nonPositiveInteger.getURI().equals(baseURI) || XSD.nonNegativeInteger.getURI().equals(baseURI) || XSD.unsignedInt.getURI().equals(baseURI) ) { numberType = NumberType.INT; } else if ( XSD.xlong.getURI().equals(baseURI) || XSD.unsignedLong.getURI().equals(baseURI) ) { numberType = NumberType.LONG; } else if ( XSD.xshort.getURI().equals(baseURI) || XSD.unsignedShort.getURI().equals(baseURI) ) { numberType = NumberType.SHORT; } else if ( XSD.xbyte.getURI().equals(baseURI) || XSD.unsignedByte.getURI().equals(baseURI) ) { numberType = NumberType.BYTE; } } private Number getNumber(String value) { Number number = null; switch (numberType) { case BYTE : number = Byte.valueOf(value); break; case DOUBLE : number = Double.valueOf(value); break; case FLOAT : number = Float.valueOf(value); break; case INT : number = Integer.valueOf(value); break; case LONG : number = Long.valueOf(value); break; case SHORT : number = Short.valueOf(value); break; } return number; } @Override public void endElement(String uri, String localName, String qName) { if ("label".equals(localName) && characters != null) { ontInfo.setLabel(characters.toString()); } if ("prefix".equals(localName) && characters != null) { ontInfo.setPrefix(characters.toString()); } if (typeURI != null && "simpleType".equals(localName)) { Datatype type = new Datatype(); type.setLocalName(this.shortName); type.setUri(typeURI); type.setLength(length); type.setFractionDigits(fractionDigits); type.setMaxExclusive(maxExclusive); type.setMaxInclusive(maxInclusive); type.setMinInclusive(minInclusive); type.setMinExclusive(minExclusive); type.setMaxExclusive(maxExclusive); type.setMinLength(minLength); type.setMaxLength(maxLength); type.setPattern(pattern); type.setTotalDigits(totalDigits); if (baseURI != null) { Datatype base = typeManager.getDatatypeByUri(baseURI); if (base == null) { String baseName = getLocalName(baseURI); base = new Datatype(); base.setLocalName(baseName); base.setUri(baseURI); typeManager.add(base); } type.setBase(base); } typeManager.add(type); typeURI = baseURI = shortName = pattern = null; length = fractionDigits = maxLength = minLength = totalDigits = null; maxExclusive = minExclusive = maxInclusive = minInclusive = null; numberType = NumberType.NONE; } characters = null; } @Override public void endDocument() { typeManager.add(ontInfo); ontInfo = null; } private String getLocalName(String uri) { int hash = uri.lastIndexOf('#'); int slash = uri.lastIndexOf('/'); int delim = Math.max(hash, slash); return uri.substring(delim+1); } private String toURI(String value) { int colon = value.indexOf(':'); return (colon < 0) ? targetNamespace + value : namespaceMap.get(value.substring(0, colon)) + value.substring(colon+1); } private String toRdfNamespace(String uri) { return (uri.endsWith("/") || uri.endsWith("#")) ? uri : uri + "#"; } private void parseNamespaces(Attributes attributes) { String targetNamespacePrefix = null; for (int i=0; i<attributes.getLength(); i++) { String name = attributes.getQName(i); if (name.startsWith("xmlns:")) { String prefix = name.substring(6); String value = toRdfNamespace(attributes.getValue(i)); namespaceMap.put(prefix, value); if (value.equals(targetNamespace)) { targetNamespacePrefix = prefix; } } } if (targetNamespacePrefix == null) { targetNamespacePrefix = defaultNamespacePrefix(targetNamespace); } ontInfo.setPrefix(targetNamespacePrefix); } private String defaultNamespacePrefix(String uri) { char last = uri.charAt(uri.length()-1); int end = (last=='#') || (last=='/') ? uri.length()-1 : uri.length(); int start = uri.lastIndexOf('/', end-1)+1; String prefix = uri.substring(start, end); return prefix; } } }