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

com.gitlab.mvysny.konsumexml.stax.JavaxXmlStreamStaxParser.kt Maven / Gradle / Ivy

The newest version!
package com.gitlab.mvysny.konsumexml.stax

import java.io.InputStream
import javax.xml.XMLConstants
import javax.xml.namespace.QName
import javax.xml.stream.XMLInputFactory
import javax.xml.stream.XMLStreamReader

/**
 * This parser uses the [XMLStreamReader] which is present in every JDK however it is not present in Android by default.
 * Call [create] to create the parser instance.
 */
public open class JavaxXmlStreamStaxParser protected constructor(public val r: XMLStreamReader) : StaxParser {
    override fun next() {
        r.next()
    }

    override val location: Location
        get() = r.location.let { Location(it.lineNumber, it.columnNumber, it.characterOffset, it.publicId, it.systemId) }

    override val eventType: StaxEventType
        get() = types[r.eventType - 1]
    override val elementName: QName
        get() = r.name

    public companion object {
        private val types = listOf(StaxEventType.StartElement, StaxEventType.EndElement, StaxEventType.ProcessingInstruction,
                StaxEventType.Characters, StaxEventType.Comment, StaxEventType.Space, StaxEventType.StartDocument,
                StaxEventType.EndDocument, StaxEventType.EntityReference, StaxEventType.Attribute, StaxEventType.DTD,
                StaxEventType.CData, StaxEventType.Namespace, StaxEventType.NotationDeclaration, StaxEventType.EntityDeclaration)

        public fun create(`in`: InputStream, systemId: String? = null,
                          xmlInputFactory: XMLInputFactory = XMLInputFactory.newInstance()): JavaxXmlStreamStaxParser {
            val xmlStreamReader: XMLStreamReader = xmlInputFactory.createXMLStreamReader(systemId, `in`)
            if (xmlStreamReader.javaClass.name.startsWith("com.bea")) {
                return JavaxXmlStreamComBeaStaxParser(xmlStreamReader)
            }
            return JavaxXmlStreamStaxParser(xmlStreamReader)
        }
    }

    private fun QName.hotfixRetardedAndroid(): QName {
        if (localPart.startsWith("xml:")) {
            // yes, Android Studio JVM will happily return attribute with localname "xml:lang" and empty namespace even though
            // it should process namespaces BY DEFAULT
            return QName(XMLConstants.XML_NS_URI, localPart.removePrefix("xml:"))
        }
        return this
    }

    override fun getAttributeName(index: Int): QName {
        val name: QName = requireNotNull(r.getAttributeName(index)) {
            "Got null attribute name, possibly index-out-of-bounds: $index not in 0..${attributeCount - 1}"
        }
        return name.hotfixRetardedAndroid()
    }

    override val attributeCount: Int
        get() = r.attributeCount

    override fun getAttributeValue(namespaceURI: String, localName: String): String? = r.getAttributeValue(namespaceURI, localName)

    override val text: String
        get() = r.text

    override fun close() {
        r.close()
    }

    override fun hasNext(): Boolean = r.hasNext()
}

/**
 * Contains workaround for https://github.com/codehaus/stax/issues/1 . See
 * https://gitlab.com/mvysny/konsume-xml/-/issues/12 for more details.
 */
internal class JavaxXmlStreamComBeaStaxParser(r: XMLStreamReader): JavaxXmlStreamStaxParser(r) {
    override val location: Location
        get() = r.location.let { Location(it.lineNumber, it.columnNumber + 1, it.characterOffset, it.publicId, it.systemId) }

    override fun getAttributeValue(namespaceURI: String, localName: String): String? {
        // use null instead of an empty string, because of https://github.com/codehaus/stax/issues/1
        return r.getAttributeValue(namespaceURI.ifBlank { null }, localName)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy