25
25
import org .metafacture .framework .annotations .Out ;
26
26
import org .metafacture .framework .helpers .DefaultStreamPipe ;
27
27
28
+ import java .util .Arrays ;
28
29
import java .util .Collections ;
30
+ import java .util .function .Function ;
29
31
30
32
/**
31
33
* Encodes a stream into MARCXML.
@@ -48,25 +50,48 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
48
50
private static final String ROOT_OPEN = "<marc:collection xmlns:marc=\" http://www.loc.gov/MARC21/slim\" xmlns:xsi=\" http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\" http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\" >" ;
49
51
private static final String ROOT_CLOSE = "</marc:collection>" ;
50
52
51
- private static final String RECORD_OPEN = "<marc:record>" ;
52
- private static final String RECORD_CLOSE = "</marc:record>" ;
53
+ private enum Tag {
53
54
54
- private static final String ATTRIBUTE_TEMPLATE = " %s=\" %s\" " ;
55
+ collection (" xmlns%s=\" " + NAMESPACE + "\" %s" ),
56
+ controlfield (" tag=\" %s\" " ),
57
+ datafield (" tag=\" %s\" ind1=\" %s\" ind2=\" %s\" " ),
58
+ leader ("" ),
59
+ record ("" ),
60
+ subfield (" code=\" %s\" " );
61
+
62
+ private static final String OPEN_TEMPLATE = "<%%s%s%s>" ;
63
+ private static final String CLOSE_TEMPLATE = "</%%s%s>" ;
64
+
65
+ private final String openTemplate ;
66
+ private final String closeTemplate ;
67
+
68
+ Tag (final String template ) {
69
+ openTemplate = String .format (OPEN_TEMPLATE , name (), template );
70
+ closeTemplate = String .format (CLOSE_TEMPLATE , name ());
71
+ }
72
+
73
+ public String open (final Object [] args ) {
74
+ return String .format (openTemplate , args );
75
+ }
76
+
77
+ public String close (final Object [] args ) {
78
+ return String .format (closeTemplate , args );
79
+ }
55
80
56
- private static final String CONTROLFIELD_OPEN_TEMPLATE = "<marc:controlfield tag=\" %s\" >" ;
57
- private static final String CONTROLFIELD_CLOSE = "</marc:controlfield>" ;
81
+ }
58
82
59
- private static final String DATAFIELD_OPEN_TEMPLATE = "<marc:datafield tag=\" %s\" ind1=\" %s\" ind2=\" %s\" >" ;
60
- private static final String DATAFIELD_CLOSE = "</marc:datafield>" ;
83
+ private static final String NAMESPACE = "http://www.loc.gov/MARC21/slim" ;
84
+ private static final String NAMESPACE_NAME = "marc" ;
85
+ private static final String NAMESPACE_PREFIX = NAMESPACE_NAME + ":" ;
86
+ private static final String NAMESPACE_SUFFIX = ":" + NAMESPACE_NAME ;
61
87
62
- private static final String SUBFIELD_OPEN_TEMPLATE = "<marc:subfield code=\" %s\" >" ;
63
- private static final String SUBFIELD_CLOSE = "</marc:subfield>" ;
88
+ private static final String SCHEMA_ATTRIBUTES = " xmlns:xsi=\" http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\" " + NAMESPACE + " http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\" " ;
64
89
65
- private static final String LEADER_OPEN_TEMPLATE = "<marc:leader>" ;
66
- private static final String LEADER_CLOSE_TEMPLATE = "</marc:leader>" ;
90
+ private static final String ATTRIBUTE_TEMPLATE = " %s=\" %s\" " ;
67
91
68
92
private static final String NEW_LINE = "\n " ;
69
93
private static final String INDENT = "\t " ;
94
+ private static final String EMPTY = "" ;
70
95
71
96
private static final String XML_DECLARATION_TEMPLATE = "<?xml version=\" %s\" encoding=\" %s\" ?>" ;
72
97
@@ -89,6 +114,9 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
89
114
90
115
private String currentEntity = "" ;
91
116
117
+ private boolean emitNamespace = true ;
118
+ private Object [] namespacePrefix = new Object []{emitNamespace ? NAMESPACE_PREFIX : EMPTY };
119
+
92
120
private int indentationLevel ;
93
121
private boolean formatted = PRETTY_PRINTED ;
94
122
private int recordAttributeOffset ;
@@ -99,6 +127,11 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
99
127
public MarcXmlEncoder () {
100
128
}
101
129
130
+ public void setEmitNamespace (final boolean emitNamespace ) {
131
+ this .emitNamespace = emitNamespace ;
132
+ namespacePrefix = new Object []{emitNamespace ? NAMESPACE_PREFIX : EMPTY };
133
+ }
134
+
102
135
/**
103
136
* Sets the flag to decide whether to omit the XML declaration.
104
137
*
@@ -151,14 +184,14 @@ public void startRecord(final String identifier) {
151
184
writeHeader ();
152
185
prettyPrintNewLine ();
153
186
}
154
- writeRaw ( ROOT_OPEN );
187
+ writeTag ( Tag . collection :: open , emitNamespace ? NAMESPACE_SUFFIX : EMPTY , emitNamespace ? SCHEMA_ATTRIBUTES : EMPTY );
155
188
prettyPrintNewLine ();
156
189
incrementIndentationLevel ();
157
190
}
158
191
atStreamStart = false ;
159
192
160
193
prettyPrintIndentation ();
161
- writeRaw ( RECORD_OPEN );
194
+ writeTag ( Tag . record :: open );
162
195
recordAttributeOffset = builder .length () - 1 ;
163
196
prettyPrintNewLine ();
164
197
@@ -169,7 +202,7 @@ public void startRecord(final String identifier) {
169
202
public void endRecord () {
170
203
decrementIndentationLevel ();
171
204
prettyPrintIndentation ();
172
- writeRaw ( RECORD_CLOSE );
205
+ writeTag ( Tag . record :: close );
173
206
prettyPrintNewLine ();
174
207
sendAndClearData ();
175
208
}
@@ -188,7 +221,7 @@ public void startEntity(final String name) {
188
221
final String ind1 = name .substring (IND1_BEGIN , IND1_END );
189
222
final String ind2 = name .substring (IND2_BEGIN , IND2_END );
190
223
prettyPrintIndentation ();
191
- writeRaw ( String . format ( DATAFIELD_OPEN_TEMPLATE , tag , ind1 , ind2 ) );
224
+ writeTag ( Tag . datafield :: open , tag , ind1 , ind2 );
192
225
prettyPrintNewLine ();
193
226
incrementIndentationLevel ();
194
227
}
@@ -199,7 +232,7 @@ public void endEntity() {
199
232
if (!currentEntity .equals (Marc21EventNames .LEADER_ENTITY )) {
200
233
decrementIndentationLevel ();
201
234
prettyPrintIndentation ();
202
- writeRaw ( DATAFIELD_CLOSE );
235
+ writeTag ( Tag . datafield :: close );
203
236
prettyPrintNewLine ();
204
237
}
205
238
currentEntity = "" ;
@@ -215,19 +248,19 @@ public void literal(final String name, final String value) {
215
248
}
216
249
else if (!writeLeader (name , value )) {
217
250
prettyPrintIndentation ();
218
- writeRaw ( String . format ( CONTROLFIELD_OPEN_TEMPLATE , name ) );
251
+ writeTag ( Tag . controlfield :: open , name );
219
252
if (value != null ) {
220
253
writeEscaped (value .trim ());
221
254
}
222
- writeRaw ( CONTROLFIELD_CLOSE );
255
+ writeTag ( Tag . controlfield :: close );
223
256
prettyPrintNewLine ();
224
257
}
225
258
}
226
259
else if (!writeLeader (currentEntity , value )) {
227
260
prettyPrintIndentation ();
228
- writeRaw ( String . format ( SUBFIELD_OPEN_TEMPLATE , name ) );
261
+ writeTag ( Tag . subfield :: open , name );
229
262
writeEscaped (value .trim ());
230
- writeRaw ( SUBFIELD_CLOSE );
263
+ writeTag ( Tag . subfield :: close );
231
264
prettyPrintNewLine ();
232
265
}
233
266
}
@@ -264,7 +297,7 @@ private void writeHeader() {
264
297
265
298
/** Closes the root tag */
266
299
private void writeFooter () {
267
- writeRaw ( ROOT_CLOSE );
300
+ writeTag ( Tag . collection :: close );
268
301
}
269
302
270
303
/**
@@ -288,7 +321,9 @@ private void writeEscaped(final String str) {
288
321
private boolean writeLeader (final String name , final String value ) {
289
322
if (name .equals (Marc21EventNames .LEADER_ENTITY )) {
290
323
prettyPrintIndentation ();
291
- writeRaw (LEADER_OPEN_TEMPLATE + value + LEADER_CLOSE_TEMPLATE );
324
+ writeTag (Tag .leader ::open );
325
+ writeRaw (value );
326
+ writeTag (Tag .leader ::close );
292
327
prettyPrintNewLine ();
293
328
294
329
return true ;
@@ -298,6 +333,12 @@ private boolean writeLeader(final String name, final String value) {
298
333
}
299
334
}
300
335
336
+ private void writeTag (final Function <Object [], String > function , final Object ... args ) {
337
+ final Object [] allArgs = Arrays .copyOf (namespacePrefix , namespacePrefix .length + args .length );
338
+ System .arraycopy (args , 0 , allArgs , namespacePrefix .length , args .length );
339
+ writeRaw (function .apply (allArgs ));
340
+ }
341
+
301
342
private void prettyPrintIndentation () {
302
343
if (formatted ) {
303
344
final String prefix = String .join ("" , Collections .nCopies (indentationLevel , INDENT ));
0 commit comments