summaryrefslogtreecommitdiff
path: root/ebics/src/main/kotlin/XmlCombinators.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ebics/src/main/kotlin/XmlCombinators.kt')
-rw-r--r--ebics/src/main/kotlin/XmlCombinators.kt98
1 files changed, 75 insertions, 23 deletions
diff --git a/ebics/src/main/kotlin/XmlCombinators.kt b/ebics/src/main/kotlin/XmlCombinators.kt
index ce1c9f37..9cb0b327 100644
--- a/ebics/src/main/kotlin/XmlCombinators.kt
+++ b/ebics/src/main/kotlin/XmlCombinators.kt
@@ -19,17 +19,62 @@
package tech.libeufin.ebics
-import org.w3c.dom.Element
+import org.w3c.dom.*
import java.io.InputStream
import java.io.StringWriter
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
+import javax.xml.parsers.*
import javax.xml.stream.XMLOutputFactory
import javax.xml.stream.XMLStreamWriter
-class XmlBuilder(private val w: XMLStreamWriter) {
- fun el(path: String, lambda: XmlBuilder.() -> Unit = {}) {
+interface XmlBuilder {
+ fun el(path: String, lambda: XmlBuilder.() -> Unit = {})
+ fun el(path: String, content: String) {
+ el(path) {
+ text(content)
+ }
+ }
+ fun attr(namespace: String, name: String, value: String)
+ fun attr(name: String, value: String)
+ fun text(content: String)
+
+ companion object {
+ fun toString(root: String, f: XmlBuilder.() -> Unit): String {
+ val factory = XMLOutputFactory.newFactory()
+ val stream = StringWriter()
+ var writer = factory.createXMLStreamWriter(stream)
+ /**
+ * NOTE: commenting out because it wasn't obvious how to output the
+ * "standalone = 'yes' directive". Manual forge was therefore preferred.
+ */
+ stream.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
+ XmlStreamBuilder(writer).el(root) {
+ this.f()
+ }
+ writer.writeEndDocument()
+ return stream.buffer.toString()
+ }
+
+ fun toDom(root: String, schema: String?, f: XmlBuilder.() -> Unit): Document {
+ val factory = DocumentBuilderFactory.newInstance();
+ factory.isNamespaceAware = true
+ val builder = factory.newDocumentBuilder();
+ val doc = builder.newDocument();
+ doc.setXmlVersion("1.0")
+ doc.setXmlStandalone(true)
+ val root = doc.createElementNS(schema, root)
+ doc.appendChild(root);
+ XmlDOMBuilder(doc, schema, root).f()
+ doc.normalize()
+ return doc
+ }
+ }
+}
+
+private class XmlStreamBuilder(private val w: XMLStreamWriter): XmlBuilder {
+ override fun el(path: String, lambda: XmlBuilder.() -> Unit) {
path.splitToSequence('/').forEach {
w.writeStartElement(it)
}
@@ -39,35 +84,42 @@ class XmlBuilder(private val w: XMLStreamWriter) {
}
}
- fun el(path: String, content: String) {
- el(path) {
- text(content)
- }
+ override fun attr(namespace: String, name: String, value: String) {
+ w.writeAttribute(namespace, name, value)
}
- fun attr(name: String, value: String) {
+ override fun attr(name: String, value: String) {
w.writeAttribute(name, value)
}
- fun text(content: String) {
+ override fun text(content: String) {
w.writeCharacters(content)
}
}
-fun constructXml(root: String, f: XmlBuilder.() -> Unit): String {
- val factory = XMLOutputFactory.newFactory()
- val stream = StringWriter()
- var writer = factory.createXMLStreamWriter(stream)
- /**
- * NOTE: commenting out because it wasn't obvious how to output the
- * "standalone = 'yes' directive". Manual forge was therefore preferred.
- */
- stream.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
- XmlBuilder(writer).el(root) {
- this.f()
- }
- writer.writeEndDocument()
- return stream.buffer.toString()
+private class XmlDOMBuilder(private val doc: Document, private val schema: String?, private var node: Element): XmlBuilder {
+ override fun el(path: String, lambda: XmlBuilder.() -> Unit) {
+ val current = node
+ path.splitToSequence('/').forEach {
+ val new = doc.createElementNS(schema, it)
+ node.appendChild(new)
+ node = new
+ }
+ lambda()
+ node = current
+ }
+
+ override fun attr(namespace: String, name: String, value: String) {
+ node.setAttributeNS(namespace, name, value)
+ }
+
+ override fun attr(name: String, value: String) {
+ node.setAttribute(name, value)
+ }
+
+ override fun text(content: String) {
+ node.appendChild(doc.createTextNode(content));
+ }
}
class DestructionError(m: String) : Exception(m)