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.
40
42
@ FluxCommand ("encode-marcxml" )
41
43
public final class MarcXmlEncoder extends DefaultStreamPipe <ObjectReceiver <String >> {
42
44
43
- 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\" >" ;
44
- private static final String ROOT_CLOSE = "</marc:collection>" ;
45
+ private enum Tag {
45
46
46
- private static final String RECORD_OPEN = "<marc:record>" ;
47
- private static final String RECORD_CLOSE = "</marc:record>" ;
47
+ collection (" xmlns%s=\" " + NAMESPACE + "\" %s" ),
48
+ controlfield (" tag=\" %s\" " ),
49
+ datafield (" tag=\" %s\" ind1=\" %s\" ind2=\" %s\" " ),
50
+ leader ("" ),
51
+ record ("" ),
52
+ subfield (" code=\" %s\" " );
48
53
49
- private static final String ATTRIBUTE_TEMPLATE = " %s=\" %s\" " ;
54
+ private static final String OPEN_TEMPLATE = "<%%s%s%s>" ;
55
+ private static final String CLOSE_TEMPLATE = "</%%s%s>" ;
56
+
57
+ private final String openTemplate ;
58
+ private final String closeTemplate ;
59
+
60
+ Tag (final String template ) {
61
+ openTemplate = String .format (OPEN_TEMPLATE , name (), template );
62
+ closeTemplate = String .format (CLOSE_TEMPLATE , name ());
63
+ }
64
+
65
+ public String open (final Object [] args ) {
66
+ return String .format (openTemplate , args );
67
+ }
68
+
69
+ public String close (final Object [] args ) {
70
+ return String .format (closeTemplate , args );
71
+ }
50
72
51
- private static final String CONTROLFIELD_OPEN_TEMPLATE = "<marc:controlfield tag=\" %s\" >" ;
52
- private static final String CONTROLFIELD_CLOSE = "</marc:controlfield>" ;
73
+ }
53
74
54
- private static final String DATAFIELD_OPEN_TEMPLATE = "<marc:datafield tag=\" %s\" ind1=\" %s\" ind2=\" %s\" >" ;
55
- private static final String DATAFIELD_CLOSE = "</marc:datafield>" ;
75
+ private static final String NAMESPACE = "http://www.loc.gov/MARC21/slim" ;
76
+ private static final String NAMESPACE_NAME = "marc" ;
77
+ private static final String NAMESPACE_PREFIX = NAMESPACE_NAME + ":" ;
78
+ private static final String NAMESPACE_SUFFIX = ":" + NAMESPACE_NAME ;
56
79
57
- private static final String SUBFIELD_OPEN_TEMPLATE = "<marc:subfield code=\" %s\" >" ;
58
- private static final String SUBFIELD_CLOSE = "</marc:subfield>" ;
80
+ 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\" " ;
59
81
60
- private static final String LEADER_OPEN_TEMPLATE = "<marc:leader>" ;
61
- private static final String LEADER_CLOSE_TEMPLATE = "</marc:leader>" ;
82
+ private static final String ATTRIBUTE_TEMPLATE = " %s=\" %s\" " ;
62
83
63
84
private static final String NEW_LINE = "\n " ;
64
85
private static final String INDENT = "\t " ;
86
+ private static final String EMPTY = "" ;
65
87
66
88
private static final String XML_DECLARATION_TEMPLATE = "<?xml version=\" %s\" encoding=\" %s\" ?>" ;
67
89
@@ -82,6 +104,9 @@ public final class MarcXmlEncoder extends DefaultStreamPipe<ObjectReceiver<Strin
82
104
private String xmlVersion ;
83
105
private String xmlEncoding ;
84
106
107
+ private boolean emitNamespace ;
108
+ private Object [] namespacePrefix ;
109
+
85
110
private String currentEntity ;
86
111
private int indentationLevel ;
87
112
private int recordAttributeOffset ;
@@ -99,6 +124,13 @@ public MarcXmlEncoder() {
99
124
100
125
this .indentationLevel = 0 ;
101
126
this .formatted = true ;
127
+
128
+ setEmitNamespace (true );
129
+ }
130
+
131
+ public void setEmitNamespace (final boolean emitNamespace ) {
132
+ this .emitNamespace = emitNamespace ;
133
+ namespacePrefix = new Object []{emitNamespace ? NAMESPACE_PREFIX : EMPTY };
102
134
}
103
135
104
136
public void omitXmlDeclaration (final boolean currentOmitXmlDeclaration ) {
@@ -130,14 +162,14 @@ public void startRecord(final String identifier) {
130
162
writeHeader ();
131
163
prettyPrintNewLine ();
132
164
}
133
- writeRaw ( ROOT_OPEN );
165
+ writeTag ( Tag . collection :: open , emitNamespace ? NAMESPACE_SUFFIX : EMPTY , emitNamespace ? SCHEMA_ATTRIBUTES : EMPTY );
134
166
prettyPrintNewLine ();
135
167
incrementIndentationLevel ();
136
168
}
137
169
atStreamStart = false ;
138
170
139
171
prettyPrintIndentation ();
140
- writeRaw ( RECORD_OPEN );
172
+ writeTag ( Tag . record :: open );
141
173
recordAttributeOffset = builder .length () - 1 ;
142
174
prettyPrintNewLine ();
143
175
@@ -148,7 +180,7 @@ public void startRecord(final String identifier) {
148
180
public void endRecord () {
149
181
decrementIndentationLevel ();
150
182
prettyPrintIndentation ();
151
- writeRaw ( RECORD_CLOSE );
183
+ writeTag ( Tag . record :: close );
152
184
prettyPrintNewLine ();
153
185
sendAndClearData ();
154
186
}
@@ -167,7 +199,7 @@ public void startEntity(final String name) {
167
199
final String ind1 = name .substring (IND1_BEGIN , IND1_END );
168
200
final String ind2 = name .substring (IND2_BEGIN , IND2_END );
169
201
prettyPrintIndentation ();
170
- writeRaw ( String . format ( DATAFIELD_OPEN_TEMPLATE , tag , ind1 , ind2 ) );
202
+ writeTag ( Tag . datafield :: open , tag , ind1 , ind2 );
171
203
prettyPrintNewLine ();
172
204
incrementIndentationLevel ();
173
205
}
@@ -178,7 +210,7 @@ public void endEntity() {
178
210
if (!currentEntity .equals (Marc21EventNames .LEADER_ENTITY )) {
179
211
decrementIndentationLevel ();
180
212
prettyPrintIndentation ();
181
- writeRaw ( DATAFIELD_CLOSE );
213
+ writeTag ( Tag . datafield :: close );
182
214
prettyPrintNewLine ();
183
215
}
184
216
currentEntity = "" ;
@@ -194,19 +226,19 @@ public void literal(final String name, final String value) {
194
226
}
195
227
else if (!writeLeader (name , value )) {
196
228
prettyPrintIndentation ();
197
- writeRaw ( String . format ( CONTROLFIELD_OPEN_TEMPLATE , name ) );
229
+ writeTag ( Tag . controlfield :: open , name );
198
230
if (value != null ) {
199
231
writeEscaped (value .trim ());
200
232
}
201
- writeRaw ( CONTROLFIELD_CLOSE );
233
+ writeTag ( Tag . controlfield :: close );
202
234
prettyPrintNewLine ();
203
235
}
204
236
}
205
237
else if (!writeLeader (currentEntity , value )) {
206
238
prettyPrintIndentation ();
207
- writeRaw ( String . format ( SUBFIELD_OPEN_TEMPLATE , name ) );
239
+ writeTag ( Tag . subfield :: open , name );
208
240
writeEscaped (value .trim ());
209
- writeRaw ( SUBFIELD_CLOSE );
241
+ writeTag ( Tag . subfield :: close );
210
242
prettyPrintNewLine ();
211
243
}
212
244
}
@@ -243,7 +275,7 @@ private void writeHeader() {
243
275
244
276
/** Closes the root tag */
245
277
private void writeFooter () {
246
- writeRaw ( ROOT_CLOSE );
278
+ writeTag ( Tag . collection :: close );
247
279
}
248
280
249
281
/** Writes a unescaped sequence */
@@ -259,7 +291,9 @@ private void writeEscaped(final String str) {
259
291
private boolean writeLeader (final String name , final String value ) {
260
292
if (name .equals (Marc21EventNames .LEADER_ENTITY )) {
261
293
prettyPrintIndentation ();
262
- writeRaw (LEADER_OPEN_TEMPLATE + value + LEADER_CLOSE_TEMPLATE );
294
+ writeTag (Tag .leader ::open );
295
+ writeRaw (value );
296
+ writeTag (Tag .leader ::close );
263
297
prettyPrintNewLine ();
264
298
265
299
return true ;
@@ -269,6 +303,12 @@ private boolean writeLeader(final String name, final String value) {
269
303
}
270
304
}
271
305
306
+ private void writeTag (final Function <Object [], String > function , final Object ... args ) {
307
+ final Object [] allArgs = Arrays .copyOf (namespacePrefix , namespacePrefix .length + args .length );
308
+ System .arraycopy (args , 0 , allArgs , namespacePrefix .length , args .length );
309
+ writeRaw (function .apply (allArgs ));
310
+ }
311
+
272
312
private void prettyPrintIndentation () {
273
313
if (formatted ) {
274
314
final String prefix = String .join ("" , Collections .nCopies (indentationLevel , INDENT ));
0 commit comments