org.coode.xml.XMLWriterImpl Maven / Gradle / Ivy
/*
* This file is part of the OWL API.
*
* The contents of this file are subject to the LGPL License, Version 3.0.
*
* Copyright (C) 2011, The University of Manchester
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see http://www.gnu.org/licenses/.
*
*
* Alternatively, the contents of this file may be used under the terms of the Apache License, Version 2.0
* in which case, the provisions of the Apache License Version 2.0 are applicable instead of those above.
*
* Copyright 2011, University of Manchester
*
* 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.coode.xml;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.StringTokenizer;
import org.semanticweb.owlapi.io.XMLUtils;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
/**
* Author: Matthew Horridge
* The University Of Manchester
* Medical Informatics Group
* Date: 30-May-2006
*
* [email protected]
* www.cs.man.ac.uk/~horridgm
*
* Developed as part of the CO-ODE project
* http://www.co-ode.org
*/
@SuppressWarnings("javadoc")
public class XMLWriterImpl implements XMLWriter {
private Stack elementStack;
protected Writer writer;
private String encoding = "";
private String xmlBase;
private URI xmlBaseURI;
private XMLWriterNamespaceManager xmlWriterNamespaceManager;
private Map entities;
private static final int TEXT_CONTENT_WRAP_LIMIT = Integer.MAX_VALUE;
private boolean preambleWritten;
private static final String PERCENT_ENTITY = "%";
public XMLWriterImpl(Writer writer, XMLWriterNamespaceManager xmlWriterNamespaceManager, String xmlBase) {
this.writer = writer;
this.xmlWriterNamespaceManager = xmlWriterNamespaceManager;
this.xmlBase = xmlBase;
xmlBaseURI = URI.create(xmlBase);
// no need to set it to UTF-8: it's supposed to be the default encoding for XML.
//Must be set correctly for the Writer anyway, or bugs will ensue.
//this.encoding = "UTF-8";
elementStack = new Stack();
setupEntities();
}
private void setupEntities() {
List namespaces = new ArrayList(xmlWriterNamespaceManager.getNamespaces());
Collections.sort(namespaces, new StringLengthOnlyComparator());
entities = new LinkedHashMap();
for (String curNamespace : namespaces) {
String curPrefix = "";
if (xmlWriterNamespaceManager.getDefaultNamespace().equals(curNamespace)) {
curPrefix = xmlWriterNamespaceManager.getDefaultPrefix();
}
else {
curPrefix = xmlWriterNamespaceManager.getPrefixForNamespace(curNamespace);
}
if (curPrefix.length() > 0) {
entities.put(curNamespace, "&" + curPrefix + ";");
}
}
}
protected String swapForEntity(String value) {
for (String curEntity : entities.keySet()) {
String entityVal = entities.get(curEntity);
if (value.length() > curEntity.length()) {
String repVal = value.replace(curEntity, entityVal);
if (repVal.length() < value.length()) {
return repVal;
}
}
}
return value;
}
public String getDefaultNamespace() {
return xmlWriterNamespaceManager.getDefaultNamespace();
}
@Override
public String getXMLBase() {
return xmlBase;
}
public URI getXMLBaseAsURI() {
return xmlBaseURI;
}
@Override
public XMLWriterNamespaceManager getNamespacePrefixes() {
return xmlWriterNamespaceManager;
}
@Override
public void setEncoding(String encoding) {
this.encoding = encoding;
}
private boolean isValidQName(String name) {
if(name == null) {
return false;
}
int colonIndex = name.indexOf(":");
boolean valid = false;
if (colonIndex == -1) {
valid = OWL2Datatype.XSD_NCNAME.getPattern().matcher(name).matches();
}
else {
valid = OWL2Datatype.XSD_NCNAME.getPattern().matcher(name.substring(0, colonIndex - 1)).matches();
if (valid) {
valid = OWL2Datatype.XSD_NAME.getPattern().matcher(name.substring(colonIndex + 1)).matches();
}
}
return valid;
}
@Override
public void setWrapAttributes(boolean b) {
if (!elementStack.isEmpty()) {
XMLElement element = elementStack.peek();
element.setWrapAttributes(b);
}
}
@Override
public void writeStartElement(String name) throws IOException {
String qName = xmlWriterNamespaceManager.getQName(name);
if ( qName == null || qName.equals(name)) {
if (!isValidQName(name)) {
// Could not generate a valid QName, therefore, we cannot
// write valid XML - just throw an exception!
throw new IllegalElementNameException(name);
}
}
XMLElement element = new XMLElement(qName, elementStack.size());
if (!elementStack.isEmpty()) {
XMLElement topElement = elementStack.peek();
if (topElement != null) {
topElement.writeElementStart(false);
}
}
elementStack.push(element);
}
@Override
public void writeEndElement() throws IOException {
// Pop the element off the stack and write it out
if (!elementStack.isEmpty()) {
XMLElement element = elementStack.pop();
element.writeElementEnd();
}
}
@Override
public void writeAttribute(String attr, String val) {
XMLElement element = elementStack.peek();
String qName = xmlWriterNamespaceManager.getQName(attr);
if (qName != null) {
element.setAttribute(qName, val);
}
}
@Override
public void writeTextContent(String text) {
XMLElement element = elementStack.peek();
element.setText(text);
}
@Override
public void writeComment(String commentText) throws IOException {
XMLElement element = new XMLElement(null, elementStack.size());
element.setText("");
if (!elementStack.isEmpty()) {
XMLElement topElement = elementStack.peek();
if (topElement != null) {
topElement.writeElementStart(false);
}
}
if (preambleWritten) {
element.writeElementStart(true);
}
else {
elementStack.push(element);
}
}
private void writeEntities(String rootName) throws IOException {
String qName = xmlWriterNamespaceManager.getQName(rootName);
if (qName == null) {
throw new IOException("Cannot create valid XML: qname for " + rootName
+ " is null");
}
writer.write("\n\n\n");
}
writer.write("]>\n\n\n");
}
@Override
public void startDocument(String rootElementName) throws IOException {
String encodingString = "";
if (encoding.length() > 0) {
encodingString = " encoding=\"" + encoding + "\"";
}
writer.write("\n");
if (XMLWriterPreferences.getInstance().isUseNamespaceEntities()) {
writeEntities(rootElementName);
}
preambleWritten = true;
while (!elementStack.isEmpty()) {
elementStack.pop().writeElementStart(true);
}
writeStartElement(rootElementName);
setWrapAttributes(true);
writeAttribute("xmlns", xmlWriterNamespaceManager.getDefaultNamespace());
if (xmlBase.length() != 0) {
writeAttribute("xml:base", xmlBase);
}
for (String curPrefix : xmlWriterNamespaceManager.getPrefixes()) {
if (curPrefix.length() > 0) {
writeAttribute("xmlns:" + curPrefix, xmlWriterNamespaceManager.getNamespaceForPrefix(curPrefix));
}
}
}
@Override
public void endDocument() throws IOException {
// Pop of each element
while (!elementStack.isEmpty()) {
writeEndElement();
}
writer.flush();
}
private static final class StringLengthOnlyComparator implements
Comparator, Serializable {
private static final long serialVersionUID = 30406L;
public StringLengthOnlyComparator() {}
@Override
public int compare(String o1, String o2) {
// Shortest string first
return o1.length() - o2.length();
}
}
public class XMLElement {
private String name;
private Map attributes;
String textContent;
private boolean startWritten;
private int indentation;
private boolean wrapAttributes;
public XMLElement(String name) {
this(name, 0);
wrapAttributes = false;
}
public XMLElement(String name, int indentation) {
this.name = name;
attributes = new LinkedHashMap();
this.indentation = indentation;
textContent = null;
startWritten = false;
}
public void setWrapAttributes(boolean b) {
wrapAttributes = b;
}
public void setAttribute(String attribute, String value) {
attributes.put(attribute, value);
}
public void setText(String content) {
textContent = content;
}
public void writeElementStart(boolean close) throws IOException {
if (!startWritten) {
startWritten = true;
insertIndentation();
if (name != null) {
writer.write('<');
writer.write(name);
writeAttributes();
if (textContent != null) {
boolean wrap = textContent.length() > TEXT_CONTENT_WRAP_LIMIT;
if (wrap) {
writeNewLine();
indentation++;
insertIndentation();
}
writer.write('>');
writeTextContent();
if (wrap) {
indentation--;
}
}
if (close) {
if (textContent != null) {
writeElementEnd();
}
else {
writer.write("/>");
writeNewLine();
}
}
else {
if (textContent == null) {
writer.write('>');
writeNewLine();
}
}
}
else {
// Name is null so by convension this is a comment
if (textContent != null) {
writer.write("\n\n\n");
StringTokenizer tokenizer = new StringTokenizer(textContent, "\n", true);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (!token.equals("\n")) {
insertIndentation();
}
writer.write(token);
}
writer.write("\n\n");
}
}
}
}
public void writeElementEnd() throws IOException {
if (name != null) {
if (!startWritten) {
writeElementStart(true);
}
else {
if (textContent == null) {
insertIndentation();
}
writer.write("");
writer.write(name);
writer.write(">");
writeNewLine();
}
}
}
private void writeAttribute(String attr, String val) throws IOException {
writer.write(attr);
writer.write('=');
writer.write('"');
if (XMLWriterPreferences.getInstance().isUseNamespaceEntities()) {
writer.write(swapForEntity(XMLUtils.escapeXML(val)));
}
else {
writer.write(XMLUtils.escapeXML(val));
}
writer.write('"');
}
private void writeAttributes() throws IOException {
for (Iterator it = attributes.keySet().iterator(); it.hasNext();) {
String attr = it.next();
String val = attributes.get(attr);
writer.write(' ');
writeAttribute(attr, val);
if (it.hasNext() && wrapAttributes) {
writer.write("\n");
indentation++;
insertIndentation();
indentation--;
}
}
}
private void writeTextContent() throws IOException {
if (textContent != null) {
writer.write(XMLUtils.escapeXML(textContent));
}
}
private void insertIndentation() throws IOException {
if (XMLWriterPreferences.getInstance().isIndenting()) {
for (int i = 0; i < indentation * XMLWriterPreferences.getInstance().getIndentSize(); i++) {
writer.write(' ');
}
}
}
private void writeNewLine() throws IOException {
writer.write('\n');
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy