refactor(common): extract shared XML Block base and reuse it in BlockContent and TaskBlock

This commit is contained in:
2026-03-26 20:43:26 +08:00
parent c5256cbc90
commit fb9b3860af
3 changed files with 145 additions and 111 deletions

View File

@@ -0,0 +1,123 @@
package work.slhaf.partner.common.base
import org.w3c.dom.Document
import org.w3c.dom.Element
import java.io.StringWriter
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
abstract class Block(
val blockName: String
) {
fun encodeToXml(): Element {
val document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.newDocument()
val root = document.createElement(blockName)
document.appendChild(root)
appendRootAttributes().forEach { attribute, value -> root.setAttribute(attribute, value) }
fillXml(document, root)
return root
}
protected open fun appendRootAttributes(): Map<String, String> {
return emptyMap()
}
fun encodeToXmlString(): String {
val transformer = TransformerFactory.newInstance().newTransformer().apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty(OutputKeys.ENCODING, "UTF-8")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
}
return StringWriter().use { writer ->
transformer.transform(DOMSource(encodeToXml()), StreamResult(writer))
writer.toString()
}
}
protected abstract fun fillXml(document: Document, root: Element)
protected fun appendTextElement(
document: Document,
parent: Element,
tagName: String,
value: Any?
): Element {
val element = document.createElement(tagName)
element.textContent = value?.toString() ?: ""
parent.appendChild(element)
return element
}
protected fun appendChildElement(
document: Document,
parent: Element,
tagName: String,
block: Element.() -> Unit = {}
): Element {
val element = document.createElement(tagName)
parent.appendChild(element)
element.block()
return element
}
protected fun appendCDataElement(
document: Document,
parent: Element,
tagName: String,
value: String?
): Element {
val element = document.createElement(tagName)
element.appendChild(document.createCDATASection(value ?: ""))
parent.appendChild(element)
return element
}
@JvmOverloads
protected fun <T> appendListElement(
document: Document,
parent: Element,
wrapperTagName: String,
itemTagName: String,
values: Iterable<T>,
block: Element.(T) -> Unit = { value ->
textContent = value?.toString() ?: ""
}
): Element {
val wrapper = document.createElement(wrapperTagName)
parent.appendChild(wrapper)
for (value in values) {
val item = document.createElement(itemTagName)
wrapper.appendChild(item)
item.block(value)
}
return wrapper
}
@JvmOverloads
protected fun <T> appendRepeatedElements(
document: Document,
parent: Element,
itemTagName: String,
values: Iterable<T>,
block: Element.(T) -> Unit = { value ->
textContent = value?.toString() ?: ""
}
) {
for (value in values) {
val item = document.createElement(itemTagName)
parent.appendChild(item)
item.block(value)
}
}
}

View File

@@ -2,16 +2,11 @@ package work.slhaf.partner.core.cognition
import org.w3c.dom.Document import org.w3c.dom.Document
import org.w3c.dom.Element import org.w3c.dom.Element
import java.io.StringWriter import work.slhaf.partner.common.base.Block
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.concurrent.locks.ReentrantReadWriteLock
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import kotlin.concurrent.write import kotlin.concurrent.write
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -318,10 +313,10 @@ private class AggregatedBlockContent(
} }
abstract class BlockContent @JvmOverloads protected constructor( abstract class BlockContent @JvmOverloads protected constructor(
val blockName: String, blockName: String,
val source: String, val source: String,
val urgency: Urgency = Urgency.NORMAL val urgency: Urgency = Urgency.NORMAL
) { ) : Block(blockName) {
enum class Urgency { enum class Urgency {
LOW, LOW,
@@ -330,111 +325,13 @@ abstract class BlockContent @JvmOverloads protected constructor(
CRITICAL CRITICAL
} }
fun encodeToXml(): Element { override fun appendRootAttributes(): Map<String, String> {
val document = DocumentBuilderFactory.newInstance() return mapOf(
.newDocumentBuilder() "source" to source,
.newDocument() "urgency" to urgency.name.lowercase(Locale.ROOT)
)
val root = document.createElement(blockName)
root.setAttribute("source", source)
root.setAttribute("urgency", urgency.name.lowercase(Locale.ROOT))
document.appendChild(root)
fillXml(document, root)
return root
} }
fun encodeToXmlString(): String {
val transformer = TransformerFactory.newInstance().newTransformer().apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty(OutputKeys.ENCODING, "UTF-8")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
}
return StringWriter().use { writer ->
transformer.transform(DOMSource(encodeToXml()), StreamResult(writer))
writer.toString()
}
}
protected abstract fun fillXml(document: Document, root: Element)
protected fun appendTextElement(
document: Document,
parent: Element,
tagName: String,
value: Any?
): Element {
val element = document.createElement(tagName)
element.textContent = value?.toString() ?: ""
parent.appendChild(element)
return element
}
protected fun appendChildElement(
document: Document,
parent: Element,
tagName: String,
block: Element.() -> Unit = {}
): Element {
val element = document.createElement(tagName)
parent.appendChild(element)
element.block()
return element
}
protected fun appendCDataElement(
document: Document,
parent: Element,
tagName: String,
value: String?
): Element {
val element = document.createElement(tagName)
element.appendChild(document.createCDATASection(value ?: ""))
parent.appendChild(element)
return element
}
@JvmOverloads
protected fun <T> appendListElement(
document: Document,
parent: Element,
wrapperTagName: String,
itemTagName: String,
values: Iterable<T>,
block: Element.(T) -> Unit = { value ->
textContent = value?.toString() ?: ""
}
): Element {
val wrapper = document.createElement(wrapperTagName)
parent.appendChild(wrapper)
for (value in values) {
val item = document.createElement(itemTagName)
wrapper.appendChild(item)
item.block(value)
}
return wrapper
}
@JvmOverloads
protected fun <T> appendRepeatedElements(
document: Document,
parent: Element,
itemTagName: String,
values: Iterable<T>,
block: Element.(T) -> Unit = { value ->
textContent = value?.toString() ?: ""
}
) {
for (value in values) {
val item = document.createElement(itemTagName)
parent.appendChild(item)
item.block(value)
}
}
} }
abstract class CommunicationBlockContent( abstract class CommunicationBlockContent(

View File

@@ -0,0 +1,14 @@
package work.slhaf.partner.module
import work.slhaf.partner.api.chat.pojo.Message
import work.slhaf.partner.common.base.Block
abstract class TaskBlock @JvmOverloads constructor(
blockName: String = "task_input"
) : Block(blockName) {
fun encodeToMessage(): Message {
return Message(Message.Character.USER, encodeToXmlString())
}
}