Skip to content

Commit

Permalink
Tidy up namespace collecting a bit more. In particular trigger full
Browse files Browse the repository at this point in the history
namepace collecting based upon more serializers. Also stabilize the
approach and retain found namespaces from the descriptor walk.
  • Loading branch information
pdvrieze committed Apr 20, 2023
1 parent 52fb6a4 commit a079576
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,16 @@ public object NodeSerializer : KSerializer<Node> {
}

override fun serialize(encoder: Encoder, value: Node) {
// Note that only for elements
encoder.encodeStructure(descriptor) {
when (value.nodeType) {
NodeConsts.DOCUMENT_NODE,
NodeConsts.DOCUMENT_FRAGMENT_NODE -> {
val type = if (value.nodeType == NodeConsts.DOCUMENT_FRAGMENT_NODE) "fragment" else "document"
encodeStringElement(descriptor, 0, type)
val children = value.childNodes.iterator().asSequence().toList()
encodeSerializableElement(descriptor, 1, ListSerializer(NodeSerializer), children)
}
NodeConsts.ELEMENT_NODE -> {
encodeStringElement(descriptor, 0, "element")
encodeSerializableElement(descriptor, 1, ElementSerializer, value as Element)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,6 @@ public class XML constructor(
serializer.serialize(encoder, value)
}

private class QNamePresentException : RuntimeException()

private fun <T> collectNamespaces(
xmlDescriptor: XmlDescriptor,
xmlEncoderBase: XmlEncoderBase,
Expand All @@ -289,6 +287,7 @@ public class XML constructor(

val pendingNamespaces = HashSet<String>()
val seenDescriptors = HashSet<XmlDescriptor>()
var hasSeenDynamicQname = false

fun collect(prefix: String, namespaceUri: String) {
if (namespaceUri !in namespaceToPrefixMap) {
Expand Down Expand Up @@ -334,32 +333,28 @@ public class XML constructor(
}

for (childDescriptor in childrenToCollect) {

if (childDescriptor.overriddenSerializer == XmlQNameSerializer) {
throw QNamePresentException()
// Only check if we haven't seen a dynamic name yet.
if (!hasSeenDynamicQname && childDescriptor.overriddenSerializer in DYNAMIC_QNAME_SERIALIZERS) {
hasSeenDynamicQname = true
}
if (childDescriptor !in seenDescriptors) {
seenDescriptors.add(childDescriptor)
collect(childDescriptor)
}
}

// TODO collect children
}

try {
collect(xmlDescriptor)
val polyCollector = ChildCollector(null)
xmlEncoderBase.serializersModule.dumpTo(polyCollector)

val polyCollector = ChildCollector(null)
xmlEncoderBase.serializersModule.dumpTo(polyCollector)
collect(xmlDescriptor)

for (childSerializer in polyCollector.children) {
collect(xmlDescriptor(childSerializer))
}
} catch (e: QNamePresentException) {
prefixToNamespaceMap.clear()
namespaceToPrefixMap.clear()
pendingNamespaces.clear()
for (childSerializer in polyCollector.children) {
collect(xmlDescriptor(childSerializer))
}

if (hasSeenDynamicQname) {
// Collect all namespaces by actually generating the full document.
val collector = NamespaceCollectingXmlWriter(prefixToNamespaceMap, namespaceToPrefixMap, pendingNamespaces)
val base = XmlEncoderBase(xmlEncoderBase.serializersModule, xmlEncoderBase.config, collector)
base.XmlEncoder(xmlDescriptor, -1).encodeSerializableValue(serializer, value)
Expand Down Expand Up @@ -638,6 +633,13 @@ public class XML constructor(
}

public companion object : StringFormat {
private val DYNAMIC_QNAME_SERIALIZERS = arrayOf(
XmlQNameSerializer,
NodeSerializer,
ElementSerializer,
CompactFragmentSerializer
)

public val defaultInstance: XML = XML {}
override val serializersModule: SerializersModule
get() = defaultInstance.serializersModule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,28 @@ import nl.adaptivity.xmlutil.XmlWriter
internal class NamespaceCollectingXmlWriter(
private val prefixToUriMap: MutableMap<String, String>,
private val uriToPrefixMap: MutableMap<String, String>,
private val plainUriMap: MutableSet<String>
): XmlWriter {
private val pendingNamespaces: MutableSet<String>
) : XmlWriter {

override var depth: Int = 0

override var indentString: String = ""

private fun recordNamespace(prefix: String, namespaceUri: String) {
if (namespaceUri !in uriToPrefixMap) {
if (prefix in prefixToUriMap) {
plainUriMap.add(namespaceUri)
if (namespaceUri.isEmpty()) { // always special case the default namespace
val existingDefaultNamespace = prefixToUriMap[""]
if (existingDefaultNamespace!=null) {
uriToPrefixMap.remove(existingDefaultNamespace)
pendingNamespaces.add(existingDefaultNamespace)
}
uriToPrefixMap[""] = ""
prefixToUriMap[""] = ""
} else if (prefix in prefixToUriMap) {
pendingNamespaces.add(namespaceUri)
} else {
if (namespaceUri in plainUriMap) {
plainUriMap.remove(namespaceUri)
if (namespaceUri in pendingNamespaces) {
pendingNamespaces.remove(namespaceUri)
}
prefixToUriMap[prefix] = namespaceUri
uriToPrefixMap[namespaceUri] = prefix
Expand All @@ -63,9 +71,9 @@ internal class NamespaceCollectingXmlWriter(

override fun attribute(namespace: String?, name: String, prefix: String?, value: String) {
if (namespace == XMLConstants.XMLNS_ATTRIBUTE_NS_URI) {
if (prefix==XMLConstants.XMLNS_ATTRIBUTE) {
if (prefix == XMLConstants.XMLNS_ATTRIBUTE) {
namespaceAttr(prefix, value)
} else if (prefix=="") {
} else if (prefix == "") {
namespaceAttr(name, value)
}
}
Expand Down

0 comments on commit a079576

Please sign in to comment.