Joiner
El DefaultJoiner proporcionado por IPF está implementado usando la API StAX, que está incluida en el lenguaje estándar de Java.
El joiner tiene una dependencia de la component store, que espera que esté poblada con componentes que, cuando se combinan con una jerarquía de componentes para definir las relaciones entre componentes, puedan unirse para formar un documento XML válido que pueda ser ingerido por otro sistema.
Namespaces
Si tus componentes agrupados usan namespaces, puede darse el caso de que necesites que los elementos hijos coincidan con el prefijo de namespace del padre. En estos casos puedes añadir una configuración adicional (configurations[0].component-hierarchy.namespace-prefix) para hacerlo en la configuración del padre, y cualquier hijo tendrá aplicado este prefijo.
Ejemplo:
ipf.bulker {
configurations = [
{
name = "IDF"
file-name-prefix = "idf-"
file-path = "/tmp/bulks"
component-hierarchy {
component-parser-name = "xml"
marker = "MPEDDIdfBlkDirDeb"
namespace-prefix = "S2SDDIdf"
children = [
{
marker = "FIToFICstmrDrctDbt"
}
]
}
}
]
}
El resultado xml de ejemplo sería:
<S2SDDIdf:FIToFICstmrDrctDbt xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.003.001.08">...</FIToFICstmrDrctDbt>
Ejemplo de uso
Este ejemplo de uso sigue el mismo escenario utilizado para demostrar el XML Splitter pero a la inversa. Poblaremos una component store, crearemos una jerarquía de componentes para determinar cómo deben unirse los componentes y finalmente proporcionaremos un output stream para que el contenido unido pueda transmitirse a donde deba ir.
Este ejemplo une solo unos pocos componentes con fines demostrativos, pero esto puede escalar a muchos más componentes. A continuación se muestra el contenido de cada uno de los componentes que se persiste en la component store.
example-library-component.xml
<library>
<name>Library of Alexandria</name>
</library>
example-book-component-1.xml
<book>
<author>Martin, Robert</author>
<title>Clean Code</title>
</book>
example-book-component-2.xml
<book>
<author>Bloch, Joshua</author>
<title>Effective Java</title>
</book>
example-chapter-component-1.xml
<chapter>
<name>Clean Code</name>
<startPage>1</startPage>
</chapter>
example-chapter-component-2.xml
<chapter>
<name>Meaningful Names</name>
<startPage>17</startPage>
</chapter>
example-chapter-component-3.xml
<chapter>
<name>Introduction</name>
<startPage>1</startPage>
</chapter>
example-chapter-component-4.xml
<chapter>
<name>Creating and Destroying Objects</name>
<startPage>5</startPage>
</chapter>
Escribamos un programa de ejemplo para primero cargar los componentes en la component store y luego procesarlos usando el XML Joiner.
ComponentStore<List<InsertionPoint>> componentStore = new InMemoryComponentStore<>();
// Create component hierarchy
var rootNode = Node.root("library", "xml");
var bookNode = rootNode.createChild("book", Collections.emptyList());
var chapterNode = bookNode.createChild("chapter", Collections.emptyList());
// Populate the component store
BulkId bulkId = BulkId.random();
var root = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.of(bulkId.getValue()))
.index(0L).marker("library")
.content(readResourceFile("example-root-component.xml"))
.custom(List.of(new InsertionPoint(bookNode, 49))).build();
var book1 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(root.getId())
.index(1L).marker("library.book")
.content(readResourceFile("example-book-component-1.xml"))
.custom(List.of(new InsertionPoint(chapterNode, 73))).build();
var book2 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(root.getId())
.index(2L).marker("library.book")
.content(readResourceFile("example-book-component-2.xml"))
.custom(List.of(new InsertionPoint(chapterNode, 76))).build();
var chapter1 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(book1.getId())
.index(3L).marker("library.book.chapter")
.content(readResourceFile("example-chapter-component-1.xml"))
.custom(Collections.emptyList()).build();
var chapter2 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(book1.getId())
.index(4L).marker("library.book.chapter")
.content(readResourceFile("example-chapter-component-2.xml"))
.custom(Collections.emptyList()).build();
var chapter3 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(book2.getId())
.index(5L).marker("library.book.chapter")
.content(readResourceFile("example-chapter-component-3.xml"))
.custom(Collections.emptyList()).build();
var chapter4 = Component.<List<InsertionPoint>>builder()
.bulkId(bulkId).id(ComponentId.random()).parentId(book2.getId())
.index(6L).marker("library.book.chapter")
.content(readResourceFile("example-chapter-component-4.xml"))
.custom(Collections.emptyList()).build();
Mono.zip(
Mono.fromCompletionStage(componentStore.save(root)),
Mono.fromCompletionStage(componentStore.save(book1)),
Mono.fromCompletionStage(componentStore.save(book2)),
Mono.fromCompletionStage(componentStore.save(chapter1)),
Mono.fromCompletionStage(componentStore.save(chapter2)),
Mono.fromCompletionStage(componentStore.save(chapter3)),
Mono.fromCompletionStage(componentStore.save(chapter4))
).block();
Joiner joiner = new XmlJoiner(componentStore);
OutputStream stream = new ByteArrayOutputStream();
var rootId = BulkComponentId.of(root.getId().getValue());
Mono.fromCompletionStage(joiner.join(rootId, rootNode, stream)).block(Duration.ofSeconds(5));
String output = stream.toString();
System.out.println(output);
Al ejecutar este código debería imprimirse lo siguiente en la consola. El formato de espacios en blanco puede verse un poco diferente debido a la forma en que los componentes se agregan al stream, pero el contenido debería ser efectivamente el mismo.
output
<library>
<name>Library of Alexandria</name>
<book>
<author>Martin, Robert</author>
<title>Clean Code</title>
<chapter>
<name>Clean Code</name>
<startPage>1</startPage>
</chapter>
<chapter>
<name>Meaningful Names</name>
<startPage>17</startPage>
</chapter>
</book>
<book>
<author>Bloch, Joshua</author>
<title>Effective Java</title>
<chapter>
<name>Introduction</name>
<startPage>1</startPage>
</chapter>
<chapter>
<name>Creating and Destroying Objects</name>
<startPage>5</startPage>
</chapter>
</book>
</library>