Commit 1831e67b authored by Jos van den Oever's avatar Jos van den Oever

Handle Relax NG <include/> elements.

parent d3dbf9d1
......@@ -94,7 +94,8 @@ public class OdfInfo {
TransformerException {
Document grammar = xml.parse(new FileInputStream(new File(rngPath)),
null);
return new OdfRngInfo(grammar);
grammar.setDocumentURI(rngPath);
return new OdfRngInfo(grammar, xml);
}
public ValidationDriver getDriver11() {
......
package odf;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
......@@ -13,15 +16,17 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class OdfRngInfo {
final HashMap<QName, LinkedList<ElementInfo>> elements;
final HashMap<QName, LinkedList<AttributeInfo>> attributes;
OdfRngInfo(Document grammar) {
OdfRngInfo(Document grammar, XML xml) throws IOException {
elements = new HashMap<QName, LinkedList<ElementInfo>>();
attributes = new HashMap<QName, LinkedList<AttributeInfo>>();
OdfRngInfoParser.handleIncludes(grammar, xml);
OdfRngInfoParser.parse(grammar, elements, attributes);
}
......@@ -364,13 +369,12 @@ class OdfRngInfoParser {
*/
static private HashMap<String, String> getNamespaces(Element e) {
final HashMap<String, String> ns = new HashMap<String, String>();
final String xmlns = "http://www.w3.org/2000/xmlns/";
ns.put("xml", "http://www.w3.org/XML/1998/namespace");
ns.put("xmlns", xmlns);
ns.put("xml", NC.xml);
ns.put("xmlns", NC.xmlns);
final NamedNodeMap atts = e.getAttributes();
for (int i = 0; i < atts.getLength(); ++i) {
final Attr a = (Attr) atts.item(i);
if (xmlns.equals(a.getNamespaceURI())) {
if (NC.xmlns.equals(a.getNamespaceURI())) {
ns.put(a.getLocalName(), a.getValue());
} else if (a.getNamespaceURI() == null
&& a.getLocalName().equals("ns")) {
......@@ -380,14 +384,105 @@ class OdfRngInfoParser {
return ns;
}
/**
* Obtain the names of the <define/> elements that are redefined before
* being included.
*
* @param includeElement
* @return
*/
static private Set<String> getOverriddenDefines(Element includeElement) {
Set<String> names = new HashSet<String>();
Element e = getFirstElementChild(includeElement);
while (e != null) {
if (isRng("define", e)) {
names.add(e.getAttribute("name"));
}
e = getNextElementSibling(e);
}
return names;
}
/**
* Copy the namespace declaration from the document element of a to that of
* b
*
* @param a
* @param b
*/
static void copyNamespaceDeclaration(Document a, Document b) {
final Element ae = a.getDocumentElement();
final Element be = b.getDocumentElement();
final NamedNodeMap atts = ae.getAttributes();
for (int i = 0; i < atts.getLength(); ++i) {
final Attr att = (Attr) atts.item(i);
if (NC.xmlns.equals(att.getNamespaceURI())) {
be.setAttributeNS(NC.xmlns, att.getName(), att.getValue());
}
}
}
/**
* Find all <include/> elements and handle them. The implementation is quite
* minimal, just to get ODF RNG files to work. The grammar is modified in
* place
*
* @param grammar
* The grammer to be modified
* @param xml
* The xml loader
* @throws IOException
*/
static void handleIncludes(Document grammar, XML xml) throws IOException {
final File dir = new File(grammar.getDocumentURI()).getParentFile();
NodeList list = grammar.getElementsByTagNameNS(NC.rng, "include");
for (int i = 0; i < list.getLength(); ++i) {
final Element includeElement = (Element) list.item(i);
final Node parent = includeElement.getParentNode();
final Set<String> names = getOverriddenDefines(includeElement);
Node n = includeElement.getFirstChild();
while (n != null) {
Node c = n.getNextSibling();
parent.insertBefore(n, includeElement);
n = c;
}
String href = includeElement.getAttribute("href");
File includeFile = new File(dir, href);
Document doc = xml.parse(new FileInputStream(includeFile), null);
n = doc.getDocumentElement().getFirstChild();
while (n != null) {
Node c = n.getNextSibling();
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) n;
if (!isRng("define", e)
|| !names.contains(e.getAttribute("name"))) {
parent.insertBefore(grammar.importNode(n, true),
includeElement);
}
} else {
parent.insertBefore(grammar.importNode(n, true),
includeElement);
}
n = c;
}
copyNamespaceDeclaration(doc, grammar);
includeElement.getParentNode().removeChild(includeElement);
}
}
/**
* Parse the grammar and place all obtained information in the two provided
* maps.
*
* @throws IOException
*/
static void parse(Document grammar,
HashMap<QName, LinkedList<ElementInfo>> elements,
HashMap<QName, LinkedList<AttributeInfo>> attributes) {
// handle the combine attributes in <define/>
RngNormalizer.normalize(grammar);
HashMap<String, String> ns = getNamespaces(grammar.getDocumentElement());
Element start = XPath
.elementIterator(grammar, "/rng:grammar/rng:start").get(0);
......
......@@ -49,7 +49,7 @@ public class Tester {
try {
doc = odfNormalizer.xml.parse(
new FileInputStream(beforePath.toFile()), odfInfo);
} catch (SAXException | IOException | TransformerException e) {
} catch (IOException e) {
throw new TestFailException("Could not read test input.", e);
}
byte result[];
......
......@@ -66,32 +66,36 @@ public class XML {
}
public Document parse(InputStream in, @Nullable OdfInfo info)
throws SAXException, IOException, TransformerException {
throws IOException {
Document doc;
try {
XMLReader reader = parser.getXMLReader();
DOMResult domResult = new DOMResult();
XMLReader reader = parser.getXMLReader();
DOMResult domResult = new DOMResult();
if (info != null) {
WhitespaceHandler whitespace = new WhitespaceHandler(
info.getRngInfo(this));
whitespace.setParent(reader);
if (info != null) {
WhitespaceHandler whitespace = new WhitespaceHandler(
info.getRngInfo(this));
whitespace.setParent(reader);
final UnitHandler unit = new UnitHandler(info.getRngInfo(this));
unit.setParent(whitespace);
PrefixHandler prefix = new PrefixHandler();
prefix.setParent(unit);
OdfFixer f = new OdfFixer(info.version);
f.setParent(prefix);
reader = f;
}
final UnitHandler unit = new UnitHandler(info.getRngInfo(this));
unit.setParent(whitespace);
PrefixHandler prefix = new PrefixHandler();
prefix.setParent(unit);
OdfFixer f = new OdfFixer(info.version);
f.setParent(prefix);
reader = f;
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
transformer.transform(new SAXSource(reader, new InputSource(in)),
domResult);
in.close();
doc = (Document) domResult.getNode();
doc.setXmlStandalone(true);
} catch (SAXException | TransformerException e) {
throw new IOException(e);
}
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
transformer.transform(new SAXSource(reader, new InputSource(in)),
domResult);
in.close();
Document doc = (Document) domResult.getNode();
doc.setXmlStandalone(true);
return doc;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment