33import static javax .xml .XMLConstants .XML_NS_PREFIX ;
44
55import com .ctc .wstx .stax .WstxEventFactory ;
6+ import com .ctc .wstx .stax .WstxInputFactory ;
67import com .ctc .wstx .stax .WstxOutputFactory ;
78import java .io .Writer ;
89import java .util .ArrayList ;
910import java .util .Collection ;
11+ import java .util .Collections ;
1012import java .util .HashMap ;
1113import java .util .Iterator ;
1214import java .util .List ;
1921import javax .xml .namespace .QName ;
2022import javax .xml .stream .XMLEventFactory ;
2123import javax .xml .stream .XMLEventWriter ;
24+ import javax .xml .stream .XMLInputFactory ;
2225import javax .xml .stream .XMLOutputFactory ;
2326import javax .xml .stream .XMLStreamException ;
2427import javax .xml .stream .events .Attribute ;
@@ -44,13 +47,15 @@ public abstract class GraphTransformer {
4447 private final Set <String > reservedPrefixes = collectReservedPrefixes ();
4548
4649 private final NodeTransformerFactory nodeTransformerFactory ;
50+ private final CustomEntityTransformer customEntityTransformer ;
4751 // maps an eipNamespace to a NamespaceSpec
4852 private final Map <String , NamespaceSpec > registeredNamespaces ;
4953
5054 protected GraphTransformer (
5155 NodeTransformerFactory nodeTransformerFactory , Collection <NamespaceSpec > namespaceSpecs ) {
5256 validatePrefixes (namespaceSpecs );
5357 this .nodeTransformerFactory = nodeTransformerFactory ;
58+ this .customEntityTransformer = new CustomEntityTransformer (initializeXMLInputFactory ());
5459 this .registeredNamespaces = new HashMap <>();
5560 this .registeredNamespaces .put (defaultNamespace ().eipNamespace (), defaultNamespace ());
5661 requiredNamespaces ().forEach (s -> this .registeredNamespaces .put (s .eipNamespace (), s ));
@@ -81,12 +86,14 @@ public final void registerNodeTransformer(EipId id, NodeTransformer transformer)
8186 *
8287 * @param graph input graph
8388 * @param output where the output XML will be written to
89+ * @param customEntities user-defined entities to be inlined in the output
8490 * @return An empty list for a successful transformation, otherwise a non-empty list of {@link
8591 * TransformationError} is returned.
8692 * @throws TransformerException thrown if a critical error preventing the transformation is
8793 * encountered
8894 */
89- public final List <TransformationError > toXml (EipGraph graph , Writer output )
95+ public final List <TransformationError > toXml (
96+ EipGraph graph , Writer output , Map <String , String > customEntities )
9097 throws TransformerException {
9198 List <TransformationError > errors = new ArrayList <>();
9299 try {
@@ -98,7 +105,9 @@ public final List<TransformationError> toXml(EipGraph graph, Writer output)
98105 StartElement root = createRootElement (graph );
99106 writer .add (root );
100107
101- writeNodes (graph , writer , errors );
108+ errors .addAll (customEntityTransformer .apply (customEntities , writer ));
109+
110+ errors .addAll (writeNodes (graph , writer ));
102111
103112 writer .add (eventFactory .createEndElement (root .getName (), null ));
104113
@@ -112,6 +121,21 @@ public final List<TransformationError> toXml(EipGraph graph, Writer output)
112121 return errors ;
113122 }
114123
124+ /**
125+ * Transform an {@link EipGraph} instance to an XML document
126+ *
127+ * @param graph input graph
128+ * @param output where the output XML will be written to
129+ * @return An empty list for a successful transformation, otherwise a non-empty list of {@link
130+ * TransformationError} is returned.
131+ * @throws TransformerException thrown if a critical error preventing the transformation is
132+ * encountered
133+ */
134+ public final List <TransformationError > toXml (EipGraph graph , Writer output )
135+ throws TransformerException {
136+ return toXml (graph , output , Collections .emptyMap ());
137+ }
138+
115139 protected abstract NamespaceSpec defaultNamespace ();
116140
117141 protected abstract Set <NamespaceSpec > requiredNamespaces ();
@@ -196,7 +220,9 @@ private Iterator<Namespace> getRootNamespaces(List<String> eipNamespaces) {
196220 .iterator ();
197221 }
198222
199- private void writeNodes (EipGraph graph , XMLEventWriter writer , List <TransformationError > errors ) {
223+ private List <TransformationError > writeNodes (EipGraph graph , XMLEventWriter writer ) {
224+ List <TransformationError > errors = new ArrayList <>();
225+
200226 // Using a for-each loop rather than stream operations due to the checked exception.
201227 // If this approach proves inefficient, an alternative is to define our own ErrorListener
202228 // interface that throws runtime exceptions.
@@ -210,6 +236,7 @@ private void writeNodes(EipGraph graph, XMLEventWriter writer, List<Transformati
210236 errors .add (error );
211237 }
212238 }
239+ return errors ;
213240 }
214241
215242 private void writeElement (XmlElement element , XMLEventWriter writer ) {
@@ -258,4 +285,11 @@ private Set<String> collectReservedPrefixes() {
258285 requiredPrefixes )
259286 .collect (Collectors .toUnmodifiableSet ());
260287 }
288+
289+ static XMLInputFactory initializeXMLInputFactory () {
290+ XMLInputFactory factory = WstxInputFactory .newFactory ();
291+ factory .setProperty (XMLInputFactory .SUPPORT_DTD , false );
292+ factory .setProperty (XMLInputFactory .IS_SUPPORTING_EXTERNAL_ENTITIES , false );
293+ return factory ;
294+ }
261295}
0 commit comments