我正在研究Boomi界面,我需要将单个xml文档合并到单个输出文档中。标准合并文档步骤无法正常工作。
所有xml文档都具有相同的结构。
第一份文件
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
第二份文件
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
第三份文件
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
预期输出
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
元素的合并与属性相同?从技术上讲,我需要将所有文档合并到CAMPO的ID属性上。
非常感谢任何帮助。
由于 纳格
我尝试了以下代码;得到过早的文件结束。错误。
import java.util.Properties;
import java.io.InputStream;
import org.jdom.input.SAXBuilder;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.xpath.XPath;
import org.jdom.output.XMLOutputter;
import groovy.util.slurpersupport.GPathResult;
import groovy.xml.StreamingMarkupBuilder;
for( int i = 0; i < dataContext.getDataCount(); i++ ) {
InputStream is = dataContext.getStream(i);
Properties props = dataContext.getProperties(i);
def xs = new XmlSlurper()
def employee = xs.parse(is);
String Encod = "UTF-8" ;
HashMap<String, GPathResult> CampoMap = new HashMap<String, GPathResult>()
employee.EMPLEADOS.EMPLEADO.PROCESO.SECCION.CAMPO.each {
CampoMap["${it.@ID}"] = it
}
new StreamingMarkupBuilder().bind {
mkp.xmlDeclaration(["version":"1.0", "encoding":"UTF-8"]);
EMPLEADOS {
EMPLEADO.PROCESO.SECCION.each {
if (CampoMap["${it.@ID}"] != null) {
it.appendNode(CampoMap["${it.@id}"].sites)
}
out << it
}
}
} .writeTo(is.newWriter(Encod))
}
dataContext.storeStream(is, props);
新代码
import groovy.util.XmlParser
import groovy.xml.MarkupBuilder
def parser = new XmlParser()
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
for( int i = 0; i < dataContext.getDataCount(); i++ ) {
InputStream is = dataContext.getStream(i);
Properties props = dataContext.getProperties(i);
def mergedDocument = (0..<dataContext.dataCount)
.collect { XmlParser.parse(dataContext.getStream(it)) }
.inject { nodeA, nodeB -> merge(nodeA, nodeB) }
builder.mkp.xmlDeclaration(version:'1.0', encoding:'UTF-8')
builder.EMPLEADOS {
doc1.EMPLEADO.each { empleado ->
EMPLEADO(empleado.attributes()) {
empleado.PROCESO.each { proceso ->
PROCESO(proceso.attributes())
}
empleado.SECCION.each { seccion ->
SECCION(seccion.attributes()) {
seccion.CAMPO.each { campo ->
CAMPO(campo.attributes(), campo.value().head())
}
}
}
}
}
}
is = mergedDocument ;
}
/*
* Category to simplify XML node comparisons.
* Basically, two Nodes are equal if their attributes are the same.
*/
// class NodeCategory {
// static boolean equals(Node me, Node other) {
// me.attributes() == other.attributes()
// }
// static boolean isCase(List<Node> nodes, Node other) {
// nodes.find { it == other } != null
// }
//}
/*
* Merges document b into document a.
* WARNING: This method is destructive; it modifies document a
* @Returns a, for convenience
*/
def merge(a, b) {
// use(NodeCategory) {
b.EMPLEADO.each { empleado ->
def existingEmpleado = a.EMPLEADO.find {
it == empleado
}
if(existingEmpleado) {
// Empleado already exists, must merge differences.
// Add any missing PROCESO nodes.
empleado.PROCESO
.findAll { !(it in existingEmpleado.PROCESO) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing SECCION nodes.
empleado.SECCION
.findAll { !(it in existingEmpleado.SECCION) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing CAMPO nodes.
empleado.SECCION.each { seccion ->
existingEmpleado.SECCION
.find { it == seccion }
.with {
seccion.CAMPO
.findAll { !(it in delegate.CAMPO) }
.each { delegate.append(it) }
}
}
} else {
// Empleado does not exist, go ahead and add it as-is.
a.append(empleado)
}
}
// }
return a
}
答案 0 :(得分:2)
首先,我应该提到组合 XML文档的通用方法是不可能的,因为合并过程是上下文的。 XML节点的合并方式取决于节点的含义。计算机无法确定数据的含义,因此您必须像程序员一样提供说明。话虽如此,这里是如何合并您的 XML文档。
import groovy.util.XmlParser
import groovy.xml.MarkupBuilder
def parser = new XmlParser()
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
def doc1 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
def doc2 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
def doc3 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
merge(doc1, doc2)
merge(doc1, doc3)
builder.mkp.xmlDeclaration(version:'1.0', encoding:'UTF-8')
builder.EMPLEADOS {
doc1.EMPLEADO.each { empleado ->
EMPLEADO(empleado.attributes()) {
empleado.PROCESO.each { proceso ->
PROCESO(proceso.attributes())
}
empleado.SECCION.each { seccion ->
SECCION(seccion.attributes()) {
seccion.CAMPO.each { campo ->
CAMPO(campo.attributes(), campo.value().head())
}
}
}
}
}
}
println writer
/*
* Category to simplify XML node comparisons.
* Basically, two Nodes are equal if their attributes are the same.
*/
class NodeCategory {
static boolean equals(Node me, Node other) {
me.attributes() == other.attributes()
}
static boolean isCase(List<Node> nodes, Node other) {
nodes.find { it == other } != null
}
}
/*
* Merges document b into document a.
* WARNING: This method is destructive; it modifies document a
* @Returns a, for convenience
*/
def merge(a, b) {
use(NodeCategory) {
b.EMPLEADO.each { empleado ->
def existingEmpleado = a.EMPLEADO.find {
it == empleado
}
if(existingEmpleado) {
// Empleado already exists, must merge differences.
// Add any missing PROCESO nodes.
empleado.PROCESO
.findAll { !(it in existingEmpleado.PROCESO) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing SECCION nodes.
empleado.SECCION
.findAll { !(it in existingEmpleado.SECCION) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing CAMPO nodes.
empleado.SECCION.each { seccion ->
existingEmpleado.SECCION
.find { it == seccion }
.with {
seccion.CAMPO
.findAll { !(it in delegate.CAMPO) }
.each { delegate.append(it) }
}
}
} else {
// Empleado does not exist, go ahead and add it as-is.
a.append(empleado)
}
}
}
return a
}
过程如下:
merge(Node a, Node b)
方法遍历节点,处理每个案例,以便a
最终成为两个文档(节点树)的组合。它基于确定b
中的节点是否已经在a
中。如果不是,则按原样添加节点。否则,相应地合并更改a
。是的,这种方法很难看,是一个真正的PITA。请为了声音编程,重构野兽。MarkupDocumentBuilder
用于处理最终节点树并生成序列化的XML文档。您可能会注意到涉及到Groovy类别。它用于简化Node
比较。
您可以使用InputStream
作为XML文档的源来调用相同的进程。它会是这样的:
def parser = new XmlParser()
def mergedDocument = (0..<dataContext.dataCount)
.collect { parser.parse(dataContext.getStream(it) }
.inject { nodeA, nodeB -> merge(nodeA, nodeB) }
然后,您可以使用mergedDocument
处理MarkupBuilder
。