2828import java .util .LinkedList ;
2929import java .util .List ;
3030import java .util .Map ;
31+ import java .util .regex .Pattern ;
3132
3233import org .metafacture .commons .ResourceUtil ;
3334import org .metafacture .framework .FluxCommand ;
4849import org .metafacture .metamorph .api .NamedValueReceiver ;
4950import org .metafacture .metamorph .api .NamedValueSource ;
5051import org .metafacture .metamorph .api .SourceLocation ;
52+ import org .slf4j .Logger ;
53+ import org .slf4j .LoggerFactory ;
5154import org .xml .sax .InputSource ;
5255
5356/**
6467@ FluxCommand ("morph" )
6568public final class Metamorph implements StreamPipe <StreamReceiver >, NamedValuePipe , Maps {
6669
70+ private static final String ELSE_NESTED_KEYWORD = "_elseNested" ;
6771 public static final String ELSE_KEYWORD = "_else" ;
72+ public static final String ELSE_FLATTENED_KEYWORD = "_elseFlattened" ;
6873 public static final char FEEDBACK_CHAR = '@' ;
6974 public static final char ESCAPE_CHAR = '\\' ;
7075 public static final String METADATA = "__meta" ;
@@ -77,8 +82,7 @@ public final class Metamorph implements StreamPipe<StreamReceiver>, NamedValuePi
7782 private static final InterceptorFactory NULL_INTERCEPTOR_FACTORY = new NullInterceptorFactory ();
7883 private static final Map <String , String > NO_VARS = Collections .emptyMap ();
7984
80- private final Registry <NamedValueReceiver > dataRegistry =
81- new WildcardRegistry <>();
85+ private final Registry <NamedValueReceiver > dataRegistry = new WildcardRegistry <>();
8286 private final List <NamedValueReceiver > elseSources = new ArrayList <>();
8387
8488 private final Map <String , Map <String , String >> maps = new HashMap <>();
@@ -94,6 +98,10 @@ public final class Metamorph implements StreamPipe<StreamReceiver>, NamedValuePi
9498 private MorphErrorHandler errorHandler = new DefaultErrorHandler ();
9599 private int recordCount ;
96100 private final List <FlushListener > recordEndListener = new ArrayList <>();
101+ private boolean elseNested ;
102+ private boolean elseNestedEntityStarted ;
103+ private String currentLiteralName ;
104+ private static final Logger LOG = LoggerFactory .getLogger (Metamorph .class );
97105
98106 protected Metamorph () {
99107 // package private
@@ -114,7 +122,6 @@ public Metamorph(final String morphDef, final InterceptorFactory interceptorFact
114122
115123 public Metamorph (final String morphDef , final Map <String , String > vars ,
116124 final InterceptorFactory interceptorFactory ) {
117-
118125 this (getInputSource (morphDef ), vars , interceptorFactory );
119126 }
120127
@@ -132,7 +139,6 @@ public Metamorph(final Reader morphDef, final InterceptorFactory interceptorFact
132139
133140 public Metamorph (final Reader morphDef , final Map <String , String > vars ,
134141 final InterceptorFactory interceptorFactory ) {
135-
136142 this (new InputSource (morphDef ), vars , interceptorFactory );
137143 }
138144
@@ -150,7 +156,6 @@ public Metamorph(final InputStream morphDef, final InterceptorFactory intercepto
150156
151157 public Metamorph (final InputStream morphDef , final Map <String , String > vars ,
152158 final InterceptorFactory interceptorFactory ) {
153-
154159 this (new InputSource (morphDef ), vars , interceptorFactory );
155160 }
156161
@@ -197,7 +202,7 @@ private void init() {
197202 flattener .setReceiver (new DefaultStreamReceiver () {
198203 @ Override
199204 public void literal (final String name , final String value ) {
200- dispatch (name , value , getElseSources ());
205+ dispatch (name , value , getElseSources (), false );
201206 }
202207 });
203208 }
@@ -215,8 +220,17 @@ public void setErrorHandler(final MorphErrorHandler errorHandler) {
215220 }
216221
217222 protected void registerNamedValueReceiver (final String source , final NamedValueReceiver data ) {
218- if (ELSE_KEYWORD .equals (source )) {
219- elseSources .add (data );
223+ if (ELSE_NESTED_KEYWORD .equals (source )) {
224+ elseNested = true ;
225+ }
226+
227+ if (ELSE_KEYWORD .equals (source ) || ELSE_FLATTENED_KEYWORD .equals (source ) || elseNested ) {
228+ if (elseSources .isEmpty ()) {
229+ elseSources .add (data );
230+ }
231+ else {
232+ LOG .warn ("Only one of '_else', '_elseFlattened' and '_elseNested' is allowed. Ignoring the superflous ones." );
233+ }
220234 } else {
221235 dataRegistry .register (source , data );
222236 }
@@ -238,12 +252,11 @@ public void startRecord(final String identifier) {
238252 final String identifierFinal = identifier ;
239253
240254 outputStreamReceiver .startRecord (identifierFinal );
241- dispatch (StandardEventNames .ID , identifierFinal , null );
255+ dispatch (StandardEventNames .ID , identifierFinal , null , false );
242256 }
243257
244258 @ Override
245259 public void endRecord () {
246-
247260 for (final FlushListener listener : recordEndListener ){
248261 listener .flush (recordCount , currentEntityCount );
249262 }
@@ -268,24 +281,20 @@ public void startEntity(final String name) {
268281 entityCountStack .push (Integer .valueOf (entityCount ));
269282
270283 flattener .startEntity (name );
271-
272-
273-
274284 }
275285
276286 @ Override
277287 public void endEntity () {
278- dispatch (flattener .getCurrentPath (), "" , null );
288+ dispatch (flattener .getCurrentPath (), "" , getElseSources (), true );
279289 currentEntityCount = entityCountStack .pop ().intValue ();
280290 flattener .endEntity ();
281-
282291 }
283292
284293
285294 @ Override
286295 public void literal (final String name , final String value ) {
296+ currentLiteralName = name ;
287297 flattener .literal (name , value );
288-
289298 }
290299
291300 @ Override
@@ -306,25 +315,48 @@ public void closeStream() {
306315 outputStreamReceiver .closeStream ();
307316 }
308317
309- protected void dispatch (final String path , final String value , final List <NamedValueReceiver > fallback ) {
310- final List <NamedValueReceiver > matchingData = findMatchingData (path , fallback );
311- if (null != matchingData ) {
318+ private void dispatch (final String path , final String value , final List <NamedValueReceiver > fallbackReceiver , final boolean endEntity ) {
319+ final List <NamedValueReceiver > matchingData = getData (path );
320+
321+ if (matchingData != null ) {
312322 send (path , value , matchingData );
313323 }
324+ else if (fallbackReceiver != null ) {
325+ if (endEntity ) {
326+ if (elseNestedEntityStarted ) {
327+ outputStreamReceiver .endEntity ();
328+ elseNestedEntityStarted = false ;
329+ }
330+ }
331+ else {
332+ final String entityName = elseNested ? flattener .getCurrentEntityName () : null ;
333+
334+ if (entityName != null ) {
335+ if (getData (entityName ) == null ) {
336+ if (!elseNestedEntityStarted ) {
337+ outputStreamReceiver .startEntity (entityName );
338+ elseNestedEntityStarted = true ;
339+ }
340+
341+ send (currentLiteralName , value , fallbackReceiver );
342+ }
343+ }
344+ else {
345+ send (path , value , fallbackReceiver );
346+ }
347+ }
348+ }
314349 }
315350
316- private List <NamedValueReceiver > findMatchingData (final String path , final List < NamedValueReceiver > fallback ) {
351+ private List <NamedValueReceiver > getData (final String path ) {
317352 final List <NamedValueReceiver > matchingData = dataRegistry .get (path );
318- if (matchingData == null || matchingData .isEmpty ()) {
319- return fallback ;
320- }
321- return matchingData ;
353+ return matchingData != null && !matchingData .isEmpty () ? matchingData : null ;
322354 }
323355
324- private void send (final String key , final String value , final List <NamedValueReceiver > dataList ) {
356+ private void send (final String path , final String value , final List <NamedValueReceiver > dataList ) {
325357 for (final NamedValueReceiver data : dataList ) {
326358 try {
327- data .receive (key , value , null , recordCount , currentEntityCount );
359+ data .receive (path , value , null , recordCount , currentEntityCount );
328360 } catch (final RuntimeException e ) {
329361 errorHandler .error (e );
330362 }
@@ -357,7 +389,7 @@ public void receive(final String name, final String value, final NamedValueSourc
357389 }
358390
359391 if (name .length () != 0 && name .charAt (0 ) == FEEDBACK_CHAR ) {
360- dispatch (name , value , null );
392+ dispatch (name , value , null , false );
361393 return ;
362394 }
363395
0 commit comments