/* * Copyright (c) 2004- michael lawley and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation * which accompanies this distribution, and is available by writing to * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contributors: * michael lawley */ package com.dstc.xmlModel; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import com.dstc.xmlModel.Attribute; import com.dstc.xmlModel.Document; import com.dstc.xmlModel.Element; import com.dstc.xmlModel.Namespace; import com.dstc.xmlModel.XmlModelFactory; /** * * * @author lawley */ public class XmlModelResourceImpl extends XMLResourceImpl { /** * */ public XmlModelResourceImpl() { super(); } /** * @param uri */ public XmlModelResourceImpl(URI uri) { super(uri); } public void doLoad(InputStream inputStream, Map options) throws IOException { try { InputSource inputSource = new InputSource(inputStream); // SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setFeature("http://xml.org/sax/features/namespaces", true); reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); reader.setContentHandler(new XmlModelHandler()); reader.parse(inputSource); } catch (SAXException e) { // Throwable t = e; // while (null != t) { // System.out.println("==============================="); // t.printStackTrace(); // t = t.getCause(); // } // e.printStackTrace(); IOException io = new IOException("Couldn't create SAX parser (SAXException)."); io.initCause(e); throw io; } catch (FactoryConfigurationError e) { // e.printStackTrace(); IOException io = new IOException("Couldn't create SAX parser (FactoryConfigurationError)."); io.initCause(e); throw io; } } class XmlModelHandler extends DefaultHandler { Stack currentElement = new Stack(); Map idMap = new HashMap(); List actions = new ArrayList(); List namespaces = new ArrayList(); Document document; public XmlModelHandler() { } public void startDocument() throws SAXException { super.startDocument(); document = XmlModelFactory.eINSTANCE.createDocument(); getContents().add(document); namespaces.clear(); } public void endDocument() throws SAXException { super.endDocument(); // post-processing for (final Iterator itr = actions.iterator(); itr.hasNext(); ) { Runnable runnable = (Runnable) itr.next(); runnable.run(); } } public void startPrefixMapping(String prefix, String uri) throws SAXException { Namespace ns = XmlModelFactory.eINSTANCE.createNamespace(); ns.setPrefix(prefix); ns.setUri(uri); namespaces.add(ns); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { boolean namespaceAware = "".equals(localName); if (namespaceAware) { localName = qName; } Element element = XmlModelFactory.eINSTANCE.createElement(); element.setName(getSimpleName(localName, qName)); element.setQName(qName); if (!currentElement.isEmpty()) { Element parent = (Element) currentElement.peek(); element.setParent(parent); } else { document.setRoot(element); } element.getNamespaces().addAll(namespaces); namespaces.clear(); int length = attributes.getLength(); element.setNamespace(resolveNamespace(element, element.getQName())); List attrs = element.getAttributes(); for (int i = 0; i < length; i++) { final Attribute attr = XmlModelFactory.eINSTANCE.createAttribute(); attr.setName(getSimpleName(attributes.getLocalName(i), attributes.getQName(i))); attr.setQName(attributes.getQName(i)); attr.setValue(attributes.getValue(i)); attrs.add(attr); attr.setNamespace(resolveNamespace(element, attr.getQName())); String type = attributes.getType(i); if ("ID".equals(type)) { idMap.put(attr.getValue(), element); } else if ("IDREF".equals(type)) { actions.add(new Runnable() { public void run() { Element refElement = (Element) idMap.get(attr.getValue()); if (null != refElement) { attr.setReference(refElement); } else { System.out.println("Warning: unresolved reference " + attr); } } }); } } currentElement.push(element); } catch (RuntimeException e) { System.out.println("Error: " + localName); e.printStackTrace(); throw e; } } public void endElement(String uri, String localName, String qName) throws SAXException { currentElement.pop(); } private void xmlns(List list, String qName, String value) { String prefix = ""; if (qName.startsWith("xmlns:")) { prefix = qName.substring(6); } else if (!qName.equals("xmlns")) { return; } Namespace ns = XmlModelFactory.eINSTANCE.createNamespace(); ns.setPrefix(prefix); ns.setUri(value); list.add(ns); } private Namespace resolveNamespace(Element element, String qName) { List namespaces = element.getNamespaces(); for (final Iterator itr = namespaces.iterator(); itr.hasNext(); ) { Namespace ns = (Namespace) itr.next(); String prefix = ns.getPrefix(); if (qName.startsWith(prefix + ":")) { return ns; } else if (prefix.length() == 0 && qName.indexOf(':') < 0) { return ns; } } if (null != element.getParent()) { // System.err.println("Look to parent..."); return resolveNamespace(element.getParent(), qName); } return null; } private String getSimpleName(String localName, String qName) { if ("".equals(localName)) { int idx = qName.indexOf(':'); if (idx >= 0) { return qName.substring(idx + 1); } else { return qName; } } else { return localName; } } } }