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

commonMain.nl.adaptivity.xmlutil.XmlBufferedWriter.kt Maven / Gradle / Ivy

There is a newer version: 0.90.0-RC3
Show newest version
/*
 * Copyright (c) 2024.
 *
 * This file is part of xmlutil.
 *
 * This file is licenced to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You should have received a copy of the license with the source distribution.
 * Alternatively, you may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION")

package nl.adaptivity.xmlutil

import nl.adaptivity.xmlutil.core.impl.NamespaceHolder
import nl.adaptivity.xmlutil.util.CombiningNamespaceContext

/**
 * Class that writes xml to a linear buffer of xml events.
 */
public class XmlBufferedWriter private constructor(
    buffer: MutableList = mutableListOf(),
    delegateNamespaceContext: IterableNamespaceContext?
) : XmlWriter {

    public constructor(buffer: MutableList = mutableListOf()) : this(buffer, null)

    private val _buffer = buffer

    /** The buffer of all written events. */
    public val buffer: List get() = _buffer

    private val namespaceHolder = NamespaceHolder()

    override val depth: Int get() = namespaceHolder.depth

    override var indentString: String
        get() = ""
        set(@Suppress("UNUSED_PARAMETER") value) {} // Buffered writers don't add synthetic elements

    override val namespaceContext: NamespaceContext = if (delegateNamespaceContext == null) {
        namespaceHolder.namespaceContext
    } else {
        // Don't use the plus operato here as we don't know that the contexts are not mutable.
        @Suppress("DEPRECATION", "TYPEALIAS_EXPANSION_DEPRECATION")
        CombiningNamespaceContext(namespaceHolder.namespaceContext, delegateNamespaceContext)
    }

    override fun setPrefix(prefix: String, namespaceUri: String) {
        namespaceHolder.addPrefixToContext(prefix, namespaceUri)
    }

    override fun getNamespaceUri(prefix: String): String? {
        return namespaceHolder.getNamespaceUri(prefix)
    }

    override fun getPrefix(namespaceUri: String?): String? {
        return namespaceUri?.let { namespaceHolder.getPrefix(it) }
    }

    override fun startTag(namespace: String?, localName: String, prefix: String?) {
        val parentContext = namespaceHolder.namespaceContext.freeze()
        namespaceHolder.incDepth()
        val effNamespace = effectiveNamespace(namespace, prefix)
        val effPrefix = effectivePrefix(prefix, effNamespace)

        _buffer.add(
            XmlEvent.StartElementEvent(
                null, effNamespace ?: "", localName, effPrefix ?: "",
                emptyArray(), parentContext, emptyList()
            )
        )
    }

    private fun effectivePrefix(prefix: String?, namespace: String?) =
        prefix ?: namespace?.let { namespaceContext.getPrefix(it) }

    private fun effectiveNamespace(namespace: String?, prefix: String?) =
        if (namespace.isNullOrEmpty()) prefix?.let { namespaceContext.getNamespaceURI(prefix) } else namespace

    override fun namespaceAttr(namespacePrefix: String, namespaceUri: String) {
        namespaceHolder.addPrefixToContext(namespacePrefix, namespaceUri)
        val localName: String
        val prefix: String
        if (namespacePrefix.isEmpty()) {
            localName = XMLConstants.XMLNS_ATTRIBUTE
            prefix = ""
        } else {
            localName = namespacePrefix
            prefix = XMLConstants.XMLNS_ATTRIBUTE
        }

        _buffer.add(
            XmlEvent.Attribute(
                null, XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
                localName, prefix, namespaceUri
            )
        )
    }

    override fun endTag(namespace: String?, localName: String, prefix: String?) {
        val effNamespace = effectiveNamespace(namespace, prefix)
        val effPrefix = effectivePrefix(prefix, effNamespace) ?: ""
        namespaceHolder.decDepth()
        _buffer.add(
            XmlEvent.EndElementEvent(
                null,
                effNamespace ?: "",
                localName,
                effPrefix,
                namespaceHolder.namespaceContext
            )
        )
    }

    override fun startDocument(version: String?, encoding: String?, standalone: Boolean?) {
        _buffer.add(XmlEvent.StartDocumentEvent(null, encoding, version, standalone))
    }

    override fun processingInstruction(text: String) {
        _buffer.add(
            XmlEvent.ProcessingInstructionEvent(null, text, "")
        )
    }

    override fun processingInstruction(target: String, data: String) {
        _buffer.add(
            XmlEvent.ProcessingInstructionEvent(null, target, data)
        )
    }

    override fun docdecl(text: String) {
        _buffer.add(XmlEvent.TextEvent(null, EventType.DOCDECL, text))
    }

    override fun attribute(namespace: String?, name: String, prefix: String?, value: String) {
        if (namespace == XMLConstants.XMLNS_ATTRIBUTE_NS_URI || prefix == XMLConstants.XMLNS_ATTRIBUTE ||
            (prefix.isNullOrEmpty() && name == XMLConstants.XMLNS_ATTRIBUTE)
        ) {
            namespaceAttr(name, value)
        } else {
            val effNamespace = effectiveNamespace(namespace, prefix)
            val effPrefix = effectivePrefix(prefix, effNamespace) ?: ""
            _buffer.add(XmlEvent.Attribute(null, effNamespace ?: "", name, effPrefix, value))
        }
    }

    override fun comment(text: String) {
        _buffer.add(XmlEvent.TextEvent(null, EventType.COMMENT, text))
    }

    override fun text(text: String) {
        _buffer.add(XmlEvent.TextEvent(null, EventType.TEXT, text))
    }

    override fun cdsect(text: String) {
        _buffer.add(XmlEvent.TextEvent(null, EventType.CDSECT, text))
    }

    override fun entityRef(text: String) {
        _buffer.add(XmlEvent.TextEvent(null, EventType.ENTITY_REF, text))
    }

    override fun ignorableWhitespace(text: String) {
        _buffer.add(
            XmlEvent.TextEvent(null, EventType.IGNORABLE_WHITESPACE, text)
        )
    }

    override fun endDocument() {
        _buffer.add(XmlEvent.EndDocumentEvent(null))
    }

    override fun close() {}

    override fun flush() {}

    public fun reader(): XmlBufferReader = XmlBufferReader(buffer.toList())

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy