All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.natpryce.xmlk.jvm_stream.kt Maven / Gradle / Ivy

Go to download

A small, extensible Java library to randomly mutate JSON documents. Useful for fuzz testing.

There is a newer version: 3.7.0.0
Show newest version
package com.natpryce.xmlk

import java.io.Reader
import java.io.StringWriter
import java.io.Writer
import javax.xml.stream.XMLInputFactory
import javax.xml.stream.XMLOutputFactory
import javax.xml.stream.XMLStreamConstants.CDATA
import javax.xml.stream.XMLStreamConstants.CHARACTERS
import javax.xml.stream.XMLStreamConstants.COMMENT
import javax.xml.stream.XMLStreamConstants.END_DOCUMENT
import javax.xml.stream.XMLStreamConstants.END_ELEMENT
import javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION
import javax.xml.stream.XMLStreamConstants.START_DOCUMENT
import javax.xml.stream.XMLStreamConstants.START_ELEMENT
import javax.xml.stream.XMLStreamReader
import javax.xml.stream.XMLStreamWriter

fun defaultInputFactory(): XMLInputFactory =
    XMLInputFactory.newFactory().apply {
        setProperty(XMLInputFactory.IS_COALESCING, true)
    }

fun defaultOutputFactory(): XMLOutputFactory =
    XMLOutputFactory.newFactory().apply {
        setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true)
    }


fun String.toXmlDocument(): XmlDocument =
    reader().use { it.readXml() }

fun XmlDocument.toXmlString(): String =
    StringWriter().also { it.writeXml(this) }.toString()


fun Reader.readXml(inputFactory: XMLInputFactory = defaultInputFactory()): XmlDocument =
    inputFactory.createXMLStreamReader(this).readXml()


fun XMLStreamReader.readXml(): XmlDocument {
    require(START_DOCUMENT, null, null)
    return XmlDocument(readChildrenUntil(END_DOCUMENT))
}

private fun XMLStreamReader.readChildrenUntil(end: Int): List {
    val children = mutableListOf()
    
    while (next() != end) {
        when (eventType) {
            START_ELEMENT -> children += readElement()
            CHARACTERS -> children += XmlText(text, asCData = false)
            CDATA -> children += XmlText(text, asCData = true)
            PROCESSING_INSTRUCTION -> children += XmlProcessingInstruction(piTarget, piData.takeIf { it.isNotEmpty() })
            COMMENT -> children += XmlComment(text)
        }
    }
    
    return children.toList()
}

private fun XMLStreamReader.readElement(): XmlElement {
    val attributes = (0 until attributeCount)
        .map { attributeQName(it) to getAttributeValue(it) }
        .toMap()
    
    val children = readChildrenUntil(END_ELEMENT)
    
    return XmlElement(elementQName(), attributes, children)
}

private fun XMLStreamReader.elementQName() =
    QName(
        localPart = localName,
        namespaceURI = namespaceURI?.takeUnless { it.isEmpty() },
        prefix = prefix?.takeUnless { it.isEmpty() })

private fun XMLStreamReader.attributeQName(i: Int) =
    QName(
        localPart = getAttributeLocalName(i),
        namespaceURI = getAttributeNamespace(i)?.takeUnless { it.isEmpty() },
        prefix = getAttributePrefix(i)?.takeUnless { it.isEmpty() })


fun Writer.writeXml(xmlDocument: XmlDocument, outputFactory: XMLOutputFactory = defaultOutputFactory()) =
    outputFactory.createXMLStreamWriter(this).writeXml(xmlDocument)

private fun XMLStreamWriter.writeXml(doc: XmlDocument) {
    writeStartDocument("UTF-8", "1.0")
    writeChildren(doc)
    writeEndDocument()
}

fun XMLStreamWriter.writeXmlNode(n: XmlNode) {
    when (n) {
        is XmlElement ->
            writeElement(n)
        is XmlText ->
            if (n.asCData) writeCData(n.text) else writeCharacters(n.text)
        is XmlProcessingInstruction ->
            writeProcessingInstruction(n.target, n.data ?: "")
        is XmlComment ->
            writeComment(n.text)
    }.let { /* check exhaustiveness */ }
}

private fun XMLStreamWriter.writeElement(n: XmlElement) {
    writeStartElement(n.name.prefix ?: "", n.name.localPart, n.name.namespaceURI ?: "")
    n.attributes.forEach { name, value ->
        writeAttribute(name.prefix ?: "", name.namespaceURI ?: "", name.localPart, value)
    }
    writeChildren(n)
    writeEndElement()
}

private fun XMLStreamWriter.writeChildren(parent: HasChildren) {
    parent.children.forEach { writeXmlNode(it) }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy