/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.xpathchooser.model;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
/**
* Generates a simplified schema from a XML document.
*
* @author Heinrich Wendel
* @author Arne Bachmann
* @author Markus Kunde
*/
public final class XSDGenerator {
/**
* For index operations.
*/
private static final int NOT_FOUND = -1;
/**
* Private constructor for utility class.
*/
private XSDGenerator() {
}
/**
* Generates a schema from a XML document.
*
* @param filename The filename of the xml file.
* @return The XSDRootElement for the given xml file.
* @throws XMLStreamException Thrown if the XML document was invalid.
* @throws IOException Thrown if the file could not be read.
*/
public static XSDDocument generate(final String filename) throws XMLStreamException, IOException {
final File file = new File(filename);
return generate(file);
}
/**
* Generates a schema from a XML document.
*
* @param file The file of the xml file.
* @return The XSDRootElement for the given xml file.
* @throws XMLStreamException Thrown if the XML document was invalid.
* @throws IOException Thrown if the file could not be read.
*/
public static XSDDocument generate(final File file) throws XMLStreamException, IOException {
final FileReader is = new FileReader(file);
final XSDDocument xsdDocument = generate(is);
is.close();
return xsdDocument;
}
/**
* Generates a schema from a XML document.
*
* @param stream The input stream of the xml file.
* @return The XSDRootElement for the given xml file.
* @throws XMLStreamException Thrown if the XML document was invalid.
*/
public static XSDDocument generate(final Reader stream) throws XMLStreamException {
final XSDDocument document = new XSDDocument();
XSDElement current = null;
final XMLInputFactory factory = XMLInputFactory.newInstance();
final XMLStreamReader parser = factory.createXMLStreamReader(stream);
int curLevel = NOT_FOUND;
final Map<Integer, List<XSDElement>> elementsOnLevel = new HashMap<Integer, List<XSDElement>>();
elementsOnLevel.put(Integer.valueOf(curLevel + 1), new ArrayList<XSDElement>());
while (true) {
int event = parser.next();
if (event == XMLStreamConstants.END_DOCUMENT) {
parser.close();
break;
} else if (event == XMLStreamConstants.START_ELEMENT) {
curLevel ++;
List<XSDElement> levelList = elementsOnLevel.get(Integer.valueOf(curLevel));
elementsOnLevel.put(Integer.valueOf(curLevel + 1), new ArrayList<XSDElement>());
XSDElement element = new XSDElement(current, parser.getLocalName());
if (current == null) {
document.getElements().add(element);
} else {
int index = current.getElements().indexOf(element);
if (index != NOT_FOUND) {
element = current.getElements().get(index);
} else {
current.getElements().add(element);
}
}
current = element;
if (!levelList.contains(element)) {
levelList.add(element);
}
if (current != null) {
for (int i = 0; i < parser.getAttributeCount(); i++) {
XSDAttribute attribute = new XSDAttribute(current, parser.getAttributeLocalName(i).toString());
int index = current.getAttributes().indexOf(attribute);
if (index != NOT_FOUND) {
attribute = current.getAttributes().get(index);
} else {
current.getAttributes().add(attribute);
}
final XSDValue attValue = new XSDValue(attribute, parser.getAttributeValue(i));
if (!attribute.getValues().contains(attValue)) {
attribute.getValues().add(attValue);
}
}
}
} else if (event == XMLStreamConstants.CHARACTERS) {
final String tmp = parser.getText().trim();
if (tmp.equals("")) {
continue;
}
final XSDValue value = new XSDValue(current, tmp);
if (current != null && !current.getValues().contains(value)) {
current.getValues().add(value);
}
} else if (current != null && event == XMLStreamConstants.END_ELEMENT) {
current = (XSDElement) current.getParent();
curLevel--;
}
}
return document;
}
}