/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.jena.rdfxml.xmlinput; import java.util.Iterator; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.Characters; import javax.xml.stream.events.Comment; import javax.xml.stream.events.DTD; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.EntityDeclaration; import javax.xml.stream.events.Namespace; import javax.xml.stream.events.ProcessingInstruction; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; /** * * Bridge StAX and SAX parsing. */ public class StAX2SAX { private final ContentHandler handler; private final LexicalHandler lhandler; private final XMLInputFactory xef; /** * Primes a converter with a SAX handler. * * Note: if handler is also LexicalHandler it will pass on lexical events. * * @param handler */ public StAX2SAX(ContentHandler handler) { this.handler = handler; this.lhandler = (handler instanceof LexicalHandler) ? (LexicalHandler) handler : NO_LEXICAL_HANDLER ; this.xef = XMLInputFactory.newInstance(); } // I'd be happier doing stream reader, but we can only convert this way public void parse(XMLStreamReader xmlReader) throws XMLStreamException, SAXException { handler.setDocumentLocator(new LocatorConv(xmlReader)); parse(xef.createXMLEventReader(xmlReader)); } /** * Consumes all StAX events and passes them on to the content handler */ public void parse(XMLEventReader xmlReader) throws XMLStreamException, SAXException { while (xmlReader.hasNext()) { XMLEvent e = xmlReader.nextEvent(); if (e.isStartDocument()) handler.startDocument(); else if (e.isEndDocument()) handler.endDocument(); else if (e.isStartElement()) emitSE(e.asStartElement()); else if (e.isEndElement()) emitEE(e.asEndElement()); else if (e.isProcessingInstruction()) emitPi((ProcessingInstruction) e); else if (e.isCharacters()) emitChars(e.asCharacters()); else if (e.isAttribute()) emitAttr((Attribute) e); else if (e.isEntityReference()) emitEnt((EntityDeclaration) e); else if (e.isNamespace()) emitNS((Namespace) e); else if (e instanceof Comment) emitComment((Comment) e); else if (e instanceof DTD) emitDTD((DTD) e); else { //System.err.println("Unknown / unhandled event type " + e); //throw new SAXException("Unknown / unhandled event type " + e); } } } private void emitSE(StartElement se) throws SAXException { @SuppressWarnings("unchecked") Iterator<Attribute> aIter = se.getAttributes() ; handler.startElement(se.getName().getNamespaceURI(), se.getName().getLocalPart(), qnameToS(se.getName()), convertAttrs(aIter)); @SuppressWarnings("unchecked") Iterator<Namespace> it = se.getNamespaces(); while (it.hasNext()) emitNS(it.next()); } private void emitEE(EndElement ee) throws SAXException { handler.endElement(ee.getName().getNamespaceURI(), ee.getName().getLocalPart(), qnameToS(ee.getName())); @SuppressWarnings("unchecked") Iterator<Namespace> it = ee.getNamespaces(); while (it.hasNext()) emitNSGone(it.next()); } private void emitPi(ProcessingInstruction pi) throws SAXException { handler.processingInstruction(pi.getTarget(), pi.getData()); } private void emitChars(Characters chars) throws SAXException { if (chars.isIgnorableWhiteSpace()) handler.ignorableWhitespace(chars.getData().toCharArray(), 0, chars.getData().length()); else handler.characters(chars.getData().toCharArray(), 0, chars.getData().length()); } private void emitAttr(Attribute attribute) { // nowt to do } private void emitEnt(EntityDeclaration entityDeclaration) { // nowt to do } private void emitNS(Namespace namespace) throws SAXException { // Safety check to work around nasty tests if (namespace.getPrefix() == null || namespace.getNamespaceURI() == null) return; handler.startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI()); } private void emitNSGone(Namespace namespace) throws SAXException { handler.endPrefixMapping(namespace.getPrefix()); } private void emitComment(Comment comment) throws SAXException { lhandler.comment(comment.getText().toCharArray(), 0, comment.getText().length()); } private void emitDTD(DTD dtd) { // Is this useful?? } private Attributes convertAttrs(Iterator<Attribute> attributes) { AttributesImpl toReturn = new AttributesImpl(); while (attributes.hasNext()) { Attribute a = attributes.next(); toReturn.addAttribute(a.getName().getNamespaceURI(), a.getName().getLocalPart(), qnameToS(a.getName()), a.getDTDType(), a.getValue()); } return toReturn; } private String qnameToS(QName name) { if (name.getPrefix().length() == 0) return name.getLocalPart(); else return name.getPrefix() + ":" + name.getLocalPart(); } static class LocatorConv implements Locator { private final XMLStreamReader reader; public LocatorConv(XMLStreamReader reader) { this.reader = reader; } @Override public final String getPublicId() { return reader.getLocation().getPublicId(); } @Override public final String getSystemId() { return reader.getLocation().getSystemId(); } @Override public final int getLineNumber() { return reader.getLocation().getLineNumber(); } @Override public final int getColumnNumber() { return reader.getLocation().getColumnNumber(); } } final static LexicalHandler NO_LEXICAL_HANDLER = new LexicalHandler() { @Override public void startDTD(String string, String string1, String string2) throws SAXException {} @Override public void endDTD() throws SAXException {} @Override public void startEntity(String string) throws SAXException {} @Override public void endEntity(String string) throws SAXException {} @Override public void startCDATA() throws SAXException {} @Override public void endCDATA() throws SAXException {} @Override public void comment(char[] chars, int i, int i1) throws SAXException {} }; }