/* * Copyright (c) 2013, University of Toronto. * * 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 edu.toronto.cs.xcurator.rdf; import edu.toronto.cs.xcurator.common.DataDocument; import edu.toronto.cs.xcurator.mapping.Mapping; import edu.toronto.cs.xcurator.mapping.XmlBasedMapping; import edu.toronto.cs.xcurator.mapping.Attribute; import edu.toronto.cs.xcurator.mapping.Schema; import edu.toronto.cs.xcurator.mapping.Reference; import edu.toronto.cs.xcurator.mapping.Relation; import edu.toronto.cs.xcurator.common.NsContext; import edu.toronto.cs.xcurator.common.XmlParser; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * * @author zhuerkan */ public class XmlBasedMappingDeserialization implements RdfGenerationStep { private final InputStream mappingFileInputStream; private final XmlParser parser; public XmlBasedMappingDeserialization(InputStream mappingFileInputStream, XmlParser parser) { this.mappingFileInputStream = mappingFileInputStream; this.parser = parser; } @Override public void process(List<DataDocument> dataDocuments, Mapping mapping) { try { if (!(mapping instanceof XmlBasedMapping)) { throw new IllegalArgumentException("The mapping needs to be XML based."); } Document mapDoc = parser.parse(mappingFileInputStream, -1); Element root = mapDoc.getDocumentElement(); // Get the namespace URI of the mapping element tags String namespaceUri = root.getNamespaceURI(); ((XmlBasedMapping) mapping).setMappingNamespaceUri(namespaceUri); // Discover the root namespace context, which maybe overrided by entities NsContext rootNsContext = new NsContext(root); mapping.setBaseNamespaceContext(rootNsContext); // Looking at all entities in the mapping NodeList nl = mapDoc.getElementsByTagNameNS(namespaceUri, XmlBasedMapping.entityTagName); for (int i = 0; i < nl.getLength(); i++) { Element entityElement = (Element) nl.item(i); // Discover the (maybe) overrided namespace context of this entity NsContext nsContext = new NsContext(rootNsContext); nsContext.discover(entityElement); // Create entity and add all attributes and relations to it Schema entity = createEntity(entityElement, nsContext); discoverAttributes(entity, entityElement, namespaceUri, nsContext); discoverRelations(entity, entityElement, namespaceUri, nsContext); // Add created entities to the mapping mapping.addEntity(entity); // Set this mapping is initialized to allow further use mapping.setInitialized(); } } catch (SAXException | IOException | ParserConfigurationException ex) { Logger.getLogger(XmlBasedMappingDeserialization.class.getName()).log(Level.SEVERE, null, ex); } } private void discoverAttributes(Schema entity, Element entityElement, String namespaceUri, NsContext nsContext) { NodeList nl = entityElement.getElementsByTagNameNS(namespaceUri, XmlBasedMapping.attributeTagName); for (int i = 0; i < nl.getLength(); i++) { Element attributeElement = (Element) nl.item(i); if (attributeElement.getParentNode() != entityElement) { continue; } Attribute attr = createAttribute(entity, attributeElement, nsContext); entity.addAttribute(attr); } } private void discoverRelations(Schema entity, Element entityElement, String namespaceUri, NsContext nsContext) { NodeList nl = entityElement.getElementsByTagNameNS(namespaceUri, XmlBasedMapping.relationTagName); for (int i = 0; i < nl.getLength(); i++) { Element relationElement = (Element) nl.item(i); if (relationElement.getParentNode() != entityElement) { continue; } Relation rel = createRelation(entity, relationElement, nsContext); // Discover the references from the children of relation element discoverReferences(rel, relationElement, namespaceUri); entity.addRelation(rel); } } private void discoverReferences(Relation relation, Element relationElement, String namespaceUri) { NodeList nl = relationElement.getElementsByTagNameNS(namespaceUri, XmlBasedMapping.referenceTagName); for (int i = 0; i < nl.getLength(); i++) { Element refElement = (Element) nl.item(i); if (refElement.getParentNode() != relationElement) { continue; } Reference ref = createReferece(refElement); relation.addReference(ref); } } private Schema createEntity(Element entityElement, NsContext nsContext) { String rdfTypeUri = getUriFromPrefixedName( entityElement.getAttribute(XmlBasedMapping.typeAttrName), nsContext); String xmlTypeUri = getUriFromPrefixedName( entityElement.getAttribute(XmlBasedMapping.xmlTypeAttrName), nsContext); String path = entityElement.getAttribute(XmlBasedMapping.pathAttrName); Schema entity = new Schema(rdfTypeUri, xmlTypeUri, nsContext); entity.addPath(path); return entity; } private Attribute createAttribute(Schema entity, Element attrElement, NsContext nsContext) { String rdfTypeUri = getUriFromPrefixedName( attrElement.getAttribute(XmlBasedMapping.nameAttrName), nsContext); String path = attrElement.getAttribute(XmlBasedMapping.pathAttrName); String xmlTypeUri = getUriFromPrefixedName( attrElement.getAttribute(XmlBasedMapping.xmlTypeAttrName), nsContext); Attribute attr = new Attribute(entity, rdfTypeUri, xmlTypeUri); attr.addPath(path); return attr; } private Relation createRelation(Schema subjectEntity, Element relationElement, NsContext nsContext) { String name = getUriFromPrefixedName( relationElement.getAttribute(XmlBasedMapping.nameAttrName), nsContext); String targetEntityXmlTypeUri = getUriFromPrefixedName( relationElement.getAttribute(XmlBasedMapping.targetEntityXmlTypeAttrName), nsContext); String path = relationElement.getAttribute(XmlBasedMapping.pathAttrName); Relation rel = new Relation(subjectEntity, null, name, targetEntityXmlTypeUri); rel.addPath(path); return rel; } private Reference createReferece(Element referenceElement) { String path = referenceElement.getAttribute(XmlBasedMapping.referencePathAttrName); String targetPath = referenceElement.getAttribute(XmlBasedMapping.referenceTargetPathAttrName); return new Reference(path, targetPath); } private String getUriFromPrefixedName(String prefixedName, NsContext nsContext) { if (prefixedName.contains(":")) { // Apply the split only 1 time to get the first prefix // There may be more prefix in the name but we choose to ignore them // for now. Need to change the way it was serialized first. String[] segs = prefixedName.split(":", 2); assert (segs.length == 2); // This is temporary. // We need more elaborate way of parsing to make sure the result is // correct. String baseUri = nsContext.getNamespaceURI(segs[0]); return (baseUri.endsWith("/") ? baseUri : baseUri + "/") + segs[1]; } else { return prefixedName; } } }