Skip to content

Instantly share code, notes, and snippets.

@chumpa
Created December 14, 2021 07:13
Show Gist options
  • Save chumpa/68cd3c15114354b9ec1a4e288b84c35d to your computer and use it in GitHub Desktop.
Save chumpa/68cd3c15114354b9ec1a4e288b84c35d to your computer and use it in GitHub Desktop.
XmlMapper.groovy
import groovy.util.slurpersupport.GPathResult
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.streamingmarkupsupport.BaseMarkupBuilder
import javax.xml.transform.OutputKeys
import javax.xml.transform.Source
import javax.xml.transform.Transformer
import javax.xml.transform.TransformerFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource
import java.time.Clock
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
class XmlMapper {
private ZoneId zoneId = null
private Clock clock = null
Instant t0, t1, t2, t3
private XmlSlurper xp = new XmlSlurper(false, true)
private GPathResult root = null
StreamingMarkupBuilder sb = new StreamingMarkupBuilder()
BaseMarkupBuilder.Document xmlbinding = null
ByteArrayOutputStream baos = null
XmlMapper(ZoneId zoneId = ZoneId.of("Europe/Moscow")) {
this.zoneId = zoneId
this.clock = Clock.system(zoneId)
}
GPathResult getRoot() {
root
}
Instant now() {
Instant.now(clock)
}
// 132 это длина текстов в айдоке
static List<String> splitText(String contentText, int limit = 132) {
return contentText.findAll(".{$limit}|.+")
}
// когда слева 0..1 и копируем направо, глядя не на содержимое а на наличие элемента/атрибута
void copy0__1(String name, GPathResult content, Closure<String> z = { String x -> x }) {
assert xmlbinding != null
int sz = content.size()
if (sz > 0) xmlbinding."$name"(z.call(content.text()))
}
String statistic() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssz").withZone(zoneId)
String pt = t1.minusMillis(t0.toEpochMilli()).toEpochMilli()
String ft = t3.minusMillis(t2.toEpochMilli()).toEpochMilli()
String x = dtf.format(this.t3)
"разбор: $pt ms, формирование xml: $ft ms, завершено в $x"
}
private GPathResult parse(def payload) {
t0 = now()
if (payload instanceof String)
root = xp.parseText(payload)
else
root = xp.parse(payload)
t1 = now()
return root
}
/**
* Оптимизировано для русских букв в строках и комментах
* @param source
* @param target
*/
long serialize(Writable source, Writer target, boolean indent = false, int indentNum = 0) {
Instant t4 = now()
baos = new ByteArrayOutputStream(512)
source.writeTo(baos.newWriter("UTF-8")) // UTF-8 здесь важно для комментариев на русском языке
baos.close()
TransformerFactory factory = TransformerFactory.newInstance()
if (indent) {
factory.setAttribute("indent-number", indentNum)
}
Transformer transformer = factory.newTransformer()
transformer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no")
transformer.setOutputProperty(OutputKeys.METHOD, "xml")
transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml")
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8")
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no")
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes")
transformer.setOutputProperty(OutputKeys.VERSION, "1.0")
Source xml = new StreamSource(new ByteArrayInputStream(baos.toByteArray()))
transformer.transform(xml, new StreamResult(target))
return now().minusMillis(t4.toEpochMilli()).toEpochMilli()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment