Skip to content

Commit c6ed0cc

Browse files
committed
Implement #207: allow mapping custom prefixes for namespace URIs
1 parent 1e41752 commit c6ed0cc

5 files changed

Lines changed: 131 additions & 21 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package tools.jackson.dataformat.xml.ser;
2+
3+
import javax.xml.stream.XMLStreamException;
4+
5+
import org.codehaus.stax2.XMLStreamWriter2;
6+
7+
import tools.jackson.dataformat.xml.util.ArgUtil;
8+
9+
/**
10+
* Entity representing binding from prefix to namespace URI, used
11+
* to determine prefix to use for given namespace URI (and dynamically
12+
* adding necessary declarations)
13+
*
14+
* @since 3.2
15+
*/
16+
public class NamespaceBinding
17+
implements XmlGeneratorWritable
18+
{
19+
private final String _prefix;
20+
21+
private final String _namespaceURI;
22+
23+
public NamespaceBinding(String prefix, String namespaceURI) {
24+
_prefix = ArgUtil.emptyToNull(prefix);
25+
_namespaceURI = ArgUtil.nonEmptyNonNull("namespaceURI", namespaceURI);
26+
}
27+
28+
@Override
29+
public void write(ToXmlGenerator xmlGen, XMLStreamWriter2 sw) throws XMLStreamException {
30+
if (_prefix == null) {
31+
sw.setDefaultNamespace(_namespaceURI);
32+
} else {
33+
sw.setPrefix(_prefix, _namespaceURI);
34+
}
35+
}
36+
37+
public boolean isDefaultNamespace() {
38+
return _prefix == null;
39+
}
40+
}
Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
11
package tools.jackson.dataformat.xml.ser;
22

3-
import javax.xml.stream.XMLStreamException;
4-
5-
import org.codehaus.stax2.XMLStreamWriter2;
6-
73
/**
8-
* Common API for XML nodes -- Comments, DTDs, Processing Instructions -- to
4+
* Base API for XML nodes -- Comments, DTDs, Processing Instructions -- to
95
* be written in Document Prolog (before actual XML Document (root node),
106
* after optional XML Declaration).
117
*
128
* @since 3.2
139
*/
1410
public interface PrologDirective
11+
extends XmlGeneratorWritable
1512
{
16-
/**
17-
* Method to call to actually write out the directive using given
18-
* {@link XMLStreamWriter2}. {@link ToXmlGenerator} is only passed
19-
* in case access to configuration was needed.
20-
*
21-
* @param xmlGen Generator that called this method: MUST NOT call
22-
* its output methods, only to be used for configuration access
23-
* @param sw Writer to use for actual output of XML event
24-
*/
25-
public void write(ToXmlGenerator xmlGen, XMLStreamWriter2 sw)
26-
throws XMLStreamException;
13+
// All we need is so far in XmlGeneratorWritable
2714
}

src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ public class ToXmlGenerator
9999
/**********************************************************************
100100
*/
101101

102+
/**
103+
* XML directives (DTD, Comments, PIs) to write, if any.
104+
*
105+
* @since 3.2
106+
*/
107+
protected List<NamespaceBinding> _namespaceBindings;
108+
102109
/**
103110
* XML directives (DTD, Comments, PIs) to write, if any.
104111
*
@@ -228,16 +235,19 @@ public ToXmlGenerator(ObjectWriteContext writeCtxt, IOContext ioCtxt,
228235

229236
/**
230237
* Method called by {@link XmlGeneratorInitializer} to inject
231-
* necessary configuration.
238+
* necessary configuration like Prolog Directives and namespace
239+
* bindings.
232240
*
233241
* @since 3.2
234242
*/
235-
public void initProlog(boolean lfBetweenPrologDirectives,
236-
List<PrologDirective> directives)
243+
public void initDocument(boolean lfBetweenPrologDirectives,
244+
List<PrologDirective> directives,
245+
List<NamespaceBinding> nsBindings)
237246
{
238247
if (_initialized) { // sanity check
239248
_reportError("Internal error: cannot call `initConfig()` after generator already initialized");
240249
}
250+
_namespaceBindings = nsBindings;
241251
_lfBetweenPrologDirectives = lfBetweenPrologDirectives;
242252
_prologDirectives = directives;
243253
}
@@ -285,7 +295,11 @@ public void initGenerator() throws JacksonException
285295
}
286296
}
287297
}
288-
298+
if (_namespaceBindings != null) {
299+
for (NamespaceBinding ns : _namespaceBindings) {
300+
ns.write(this, _xmlWriter);
301+
}
302+
}
289303
} catch (XMLStreamException e) {
290304
StaxUtil.throwAsWriteException(e, this);
291305
}

src/main/java/tools/jackson/dataformat/xml/ser/XmlGeneratorInitializer.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5+
import java.util.Map;
56

67
import tools.jackson.core.JacksonException;
78
import tools.jackson.core.JsonGenerator;
@@ -31,16 +32,26 @@
3132
public class XmlGeneratorInitializer
3233
implements GeneratorInitializer
3334
{
35+
/**
36+
* Prolog Directives to pass for generator to write.
37+
*/
3438
protected List<PrologDirective> _directives;
3539

40+
/**
41+
* Namespace bindings (prefix to URL) to register with
42+
* generator.
43+
*/
44+
protected List<NamespaceBinding> _namespaceBindings;
45+
3646
protected boolean _addLfBetweenPrologDirectives = true;
3747

3848
protected boolean _hasDTD;
3949

4050
@Override
4151
public void initialize(SerializationConfig config, JsonGenerator g) throws JacksonException {
4252
if (g instanceof ToXmlGenerator xg) {
43-
xg.initProlog(_addLfBetweenPrologDirectives, _directives);
53+
xg.initDocument(_addLfBetweenPrologDirectives, _directives,
54+
_namespaceBindings);
4455
}
4556
}
4657

@@ -124,6 +135,39 @@ public XmlGeneratorInitializer addPI(String target, String data) {
124135
return _add(new PrologPI(target, data));
125136
}
126137

138+
/**
139+
* Method for specifying namespace URI to preferentially bind to the
140+
* "default namespace" (one used when element has no prefix).
141+
* This will guide underlying generator to add necessary
142+
* declarations when actually writing elements with matching
143+
* namespace URI.
144+
*
145+
* @param namespaceURI URI of the default namespace
146+
*
147+
* @return This initializer for call chaining
148+
*/
149+
public XmlGeneratorInitializer addDefaultNamespace(String namespaceURI) {
150+
return addNamespace(null, namespaceURI);
151+
}
152+
153+
/**
154+
* Method for adding a mapping (binding) between given prefix and matching
155+
* namespace URI. This will guide underlying generator to add necessary
156+
* declarations when actually writing namespaced attributes and elements.
157+
*
158+
* @param prefix Prefix to use for namespace
159+
* @param namespaceURI URI of the namespace
160+
*
161+
* @return This initializer for call chaining
162+
*/
163+
public XmlGeneratorInitializer addNamespace(String prefix, String namespaceURI) {
164+
if (_namespaceBindings == null) {
165+
_namespaceBindings = new ArrayList<>();
166+
}
167+
_namespaceBindings.add(new NamespaceBinding(prefix, namespaceURI));
168+
return this;
169+
}
170+
127171
protected XmlGeneratorInitializer _add(PrologDirective d) {
128172
if (_directives == null) {
129173
_directives = new ArrayList<>();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package tools.jackson.dataformat.xml.ser;
2+
3+
import javax.xml.stream.XMLStreamException;
4+
5+
import org.codehaus.stax2.XMLStreamWriter2;
6+
7+
/**
8+
* Common API for XML entities to write via {@link ToXmlGenerator}.
9+
*
10+
* @since 3.2
11+
*/
12+
public interface XmlGeneratorWritable
13+
{
14+
/**
15+
* Method to call to actually write out the entity using given
16+
* {@link XMLStreamWriter2}. {@link ToXmlGenerator} is only passed
17+
* in case access to configuration was needed.
18+
*
19+
* @param xmlGen Generator that called this method: MUST NOT call
20+
* its output methods, only to be used for configuration access
21+
* @param sw Writer to use for actual output of XML event
22+
*/
23+
public void write(ToXmlGenerator xmlGen, XMLStreamWriter2 sw)
24+
throws XMLStreamException;
25+
}

0 commit comments

Comments
 (0)