Skip to content

Commit dec80f5

Browse files
committed
Added support for data-driven entity-names in Metamorph:
Usage: <entity> <entity-name> <data source="inp"> </entity-name> <data source="content"> <data source="moreContent"> </entity>
1 parent 79441b4 commit dec80f5

File tree

6 files changed

+196
-12
lines changed

6 files changed

+196
-12
lines changed

src/main/java/org/culturegraph/mf/morph/AbstractMetamorphDomWalker.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,14 @@ public static enum MMTAG {
5353
* XML attributes
5454
*/
5555
public static enum ATTRITBUTE {
56-
VERSION("version"), SOURCE("source"), VALUE("value"), NAME("name"), CLASS("class"), DEFAULT("default"), ENTITY_MARKER(
57-
"entityMarker"), FLUSH_WITH("flushWith");
56+
VERSION("version"),
57+
SOURCE("source"),
58+
VALUE("value"),
59+
NAME("name"),
60+
CLASS("class"),
61+
DEFAULT("default"),
62+
ENTITY_MARKER("entityMarker"),
63+
FLUSH_WITH("flushWith");
5864

5965
private final String string;
6066

@@ -71,6 +77,7 @@ public String getString() {
7177
private static final String MAP = "map";
7278
private static final String MACRO = "call-macro";
7379
private static final String POSTPROCESS = "postprocess";
80+
private static final String ENTITY_NAME = "entity-name";
7481
private static final String SCHEMA_FILE = "schemata/metamorph.xsd";
7582
private static final int LOWEST_COMPATIBLE_VERSION = 1;
7683
private static final int CURRENT_VERSION = 1;
@@ -255,13 +262,17 @@ private void handleMacros(final Node node) {
255262

256263
protected abstract void handleFunctionDefinition(final Node functionDefNode);
257264

265+
protected abstract void enterData(Node node);
266+
258267
protected abstract void exitData(Node node);
259268

260-
protected abstract void enterData(Node node);
269+
protected abstract void enterCollect(Node node);
261270

262271
protected abstract void exitCollect(Node node);
263272

264-
protected abstract void enterCollect(Node node);
273+
protected abstract void enterName(Node node);
274+
275+
protected abstract void exitName(Node node);
265276

266277
protected abstract void handleFunction(Node functionNode);
267278

@@ -272,6 +283,10 @@ private void handleRule(final Node node) {
272283
for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
273284
if (POSTPROCESS.equals(child.getLocalName())) {
274285
handlePostprocess(child);
286+
} else if (ENTITY_NAME.equals(child.getLocalName())) {
287+
enterName(child);
288+
handleRule(child.getFirstChild());
289+
exitName(child);
275290
} else {
276291
handleRule(child);
277292
}

src/main/java/org/culturegraph/mf/morph/MorphBuilder.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.culturegraph.mf.exceptions.MorphDefException;
2323
import org.culturegraph.mf.morph.collectors.Collect;
24+
import org.culturegraph.mf.morph.collectors.Entity;
2425
import org.culturegraph.mf.morph.functions.Function;
2526
import org.culturegraph.mf.types.MultiMap;
2627
import org.culturegraph.mf.util.reflection.ObjectFactory;
@@ -41,6 +42,7 @@ public final class MorphBuilder extends AbstractMetamorphDomWalker {
4142
private final Metamorph metamorph;
4243
private final Deque<Collect> collectStack;
4344
private Data data;
45+
private Entity entity;
4446

4547
protected MorphBuilder(final Metamorph metamorph) {
4648
super();
@@ -133,6 +135,11 @@ protected void enterData(final Node dataNode) {
133135
data = new Data();
134136
data.setName(resolvedAttribute(dataNode, ATTRITBUTE.NAME));
135137
metamorph.registerNamedValueReceiver(source, data);
138+
139+
if (entity != null) {
140+
entity.setNameSource(data);
141+
entity = null;
142+
}
136143
}
137144

138145
@Override
@@ -142,9 +149,19 @@ protected void exitData(final Node node) {
142149
} else {
143150
final Collect parent = collectStack.peek();
144151
data.endPipe(parent);
145-
parent.addNamedValueSource(data);
152+
parent.addNamedValueSource(data);
146153
}
147-
data = null;
154+
data = null;
155+
}
156+
157+
@Override
158+
protected void enterName(final Node nameNode) {
159+
entity = (Entity) collectStack.peek();
160+
}
161+
162+
@Override
163+
protected void exitName(final Node nameNode) {
164+
entity = null;
148165
}
149166

150167
@Override
@@ -159,7 +176,12 @@ protected void enterCollect(final Node node) {
159176
final Collect collect = getCollectFactory().newInstance(node.getLocalName(), attributes, metamorph);
160177

161178
collectStack.push(collect);
162-
}
179+
180+
if (entity != null) {
181+
entity.setNameSource(collect);
182+
entity = null;
183+
}
184+
}
163185

164186
@Override
165187
protected void exitCollect(final Node node) {
@@ -171,7 +193,7 @@ protected void exitCollect(final Node node) {
171193
parent.addNamedValueSource(collect);
172194
collect.endPipe(parent);
173195
}
174-
// must be set after recursive calls to flush decendents before parent
196+
// must be set after recursive calls to flush descendants before parent
175197
final String flushWith = resolvedAttribute(node, ATTRITBUTE.FLUSH_WITH);
176198
if (null != flushWith) {
177199
collect.setWaitForFlush(true);

src/main/java/org/culturegraph/mf/morph/MorphVisualizer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,18 @@ protected void exitCollect(final Node node) {
229229

230230
}
231231

232+
@Override
233+
protected void enterName(final Node node) {
234+
// TODO Auto-generated method stub
235+
236+
}
237+
238+
@Override
239+
protected void exitName(final Node node) {
240+
// TODO Auto-generated method stub
241+
242+
}
243+
232244
private void exit(final Node node) {
233245
String name = resolvedAttribute(node, ATTRITBUTE.NAME);
234246
if (name == null) {

src/main/java/org/culturegraph/mf/morph/collectors/Entity.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030

3131
/**
32-
* Corresponds to the <code>&lt;collect-entity&gt;</code> tag.
32+
* Corresponds to the <code>&lt;entity&gt;</code> tag.
3333
*
3434
* @author Markus Michael Geipel
3535
*/
@@ -41,11 +41,17 @@ public final class Entity extends AbstractCollect {
4141
private final List<NamedValueSource> sourceList = new ArrayList<NamedValueSource>();
4242
private final Set<NamedValueSource> sourcesLeft = new HashSet<NamedValueSource>();
4343
private final StreamBuffer buffer = new StreamBuffer();
44+
45+
private NamedValueSource nameSource;
4446

4547
public Entity(final Metamorph metamorph) {
4648
super(metamorph);
4749
}
4850

51+
public void setNameSource(final NamedValueSource nameSource) {
52+
this.nameSource = nameSource;
53+
}
54+
4955
@Override
5056
protected void emit() {
5157
final NamedValueReceiver namedValueReceiver = getNamedValueReceiver();
@@ -72,7 +78,9 @@ private void write(final StreamReceiver receiver) {
7278

7379
@Override
7480
protected void receive(final String name, final String value, final NamedValueSource source) {
75-
if (source instanceof Entity) {
81+
if (source == nameSource) {
82+
setName(value);
83+
} else if (source instanceof Entity) {
7684
final Entity child = (Entity) source;
7785
child.write(buffer);
7886
}else{
@@ -97,4 +105,5 @@ public void onNamedValueSourceAdded(final NamedValueSource namedValueSource) {
97105
sourceList.add(namedValueSource);
98106
sourcesLeft.add(namedValueSource);
99107
}
108+
100109
}

src/main/resources/schemata/metamorph.xsd

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
</complexType>
5555
</element>
5656

57-
<element name="annotation" type="string" />
5857
<element name="name" type="string" />
58+
<element name="annotation" type="string" />
5959

6060
<element name="macros">
6161
<annotation><documentation>Holds macro definitions</documentation></annotation>
@@ -269,10 +269,13 @@
269269
<annotation><documentation>Create an entity</documentation></annotation>
270270
<complexType>
271271
<choice minOccurs="1" maxOccurs="unbounded">
272+
<element ref="tns:entity-name" minOccurs="0" maxOccurs="1" />
272273
<group ref="tns:literal-rule" minOccurs="0" maxOccurs="unbounded" />
273274
<element ref="tns:entity" />
274275
</choice>
275-
<attribute name="name" type="string" use="required" />
276+
<attribute name="name" type="string" use="optional">
277+
<annotation><documentation>Name of the entity. If not given the entity must have an entity-name element.</documentation></annotation>
278+
</attribute>
276279
<attribute name="reset" type="boolean" use="optional"
277280
default="false" />
278281
<attribute name="sameEntity" type="boolean" use="optional"
@@ -299,6 +302,20 @@
299302
</complexType>
300303
</element>
301304

305+
306+
307+
<element name="entity-name">
308+
<annotation><documentation>
309+
The literal defined here is used as the name of the entity.
310+
It overrides the value of the name-attribute of the entity element.
311+
</documentation></annotation>
312+
<complexType>
313+
<sequence>
314+
<group ref="tns:literal-rule" minOccurs="1" maxOccurs="1" />
315+
</sequence>
316+
</complexType>
317+
</element>
318+
302319

303320

304321
<element name="postprocess">

src/test/java/org/culturegraph/mf/morph/collectors/EntityTest.xml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,113 @@
262262
</result>
263263
</test-case>
264264

265+
<test-case name="shouldGetNameFromDataInEntityName">
266+
<input type="text/x-cg+xml">
267+
<cgxml:cgxml version="1.0">
268+
<cgxml:records>
269+
<cgxml:record id="1x">
270+
<cgxml:literal name="data1" value="a1" />
271+
<cgxml:literal name="data1" value="a2" />
272+
<cgxml:literal name="data2" value="b" />
273+
</cgxml:record>
274+
<cgxml:record id="2x">
275+
<cgxml:literal name="data2" value="c" />
276+
<cgxml:literal name="data1" value="d" />
277+
</cgxml:record>
278+
</cgxml:records>
279+
</cgxml:cgxml>
280+
</input>
281+
282+
<transformation type="text/x-metamorph+xml">
283+
<mm:metamorph version="1">
284+
<mm:rules>
285+
<mm:entity>
286+
<mm:entity-name>
287+
<mm:data source="data1">
288+
<mm:compose prefix="entity:" />
289+
</mm:data>
290+
</mm:entity-name>
291+
<mm:data source="data1" name="l1" />
292+
<mm:data source="data2" name="l2" />
293+
</mm:entity>
294+
</mm:rules>
295+
</mm:metamorph>
296+
</transformation>
297+
298+
<result type="text/x-cg+xml">
299+
<cgxml:cgxml version="1.0">
300+
<cgxml:records>
301+
<cgxml:record id="1x">
302+
<cgxml:entity name="entity:a2">
303+
<cgxml:literal name="l1" value="a1" />
304+
<cgxml:literal name="l1" value="a2" />
305+
<cgxml:literal name="l2" value="b" />
306+
</cgxml:entity>
307+
</cgxml:record>
308+
<cgxml:record id="2x">
309+
<cgxml:entity name="entity:d">
310+
<cgxml:literal name="l2" value="c" />
311+
<cgxml:literal name="l1" value="d" />
312+
</cgxml:entity>
313+
</cgxml:record>
314+
</cgxml:records>
315+
</cgxml:cgxml>
316+
</result>
317+
</test-case>
318+
319+
<test-case name="shouldGetNameFromCollectInEntityName">
320+
<input type="text/x-cg+xml">
321+
<cgxml:cgxml version="1.0">
322+
<cgxml:records>
323+
<cgxml:record id="1x">
324+
<cgxml:literal name="data1" value="a1" />
325+
<cgxml:literal name="data1" value="a2" />
326+
<cgxml:literal name="data2" value="b" />
327+
</cgxml:record>
328+
<cgxml:record id="2x">
329+
<cgxml:literal name="data2" value="c" />
330+
<cgxml:literal name="data1" value="d" />
331+
</cgxml:record>
332+
</cgxml:records>
333+
</cgxml:cgxml>
334+
</input>
335+
336+
<transformation type="text/x-metamorph+xml">
337+
<mm:metamorph version="1">
338+
<mm:rules>
339+
<mm:entity>
340+
<mm:entity-name>
341+
<mm:combine name="" value="entity:${a},${b}">
342+
<mm:data source="data1" name="a" />
343+
<mm:data source="data2" name="b" />
344+
</mm:combine>
345+
</mm:entity-name>
346+
<mm:data source="data1" name="l1" />
347+
<mm:data source="data2" name="l2" />
348+
</mm:entity>
349+
</mm:rules>
350+
</mm:metamorph>
351+
</transformation>
352+
353+
<result type="text/x-cg+xml">
354+
<cgxml:cgxml version="1.0">
355+
<cgxml:records>
356+
<cgxml:record id="1x">
357+
<cgxml:entity name="entity:a2,b">
358+
<cgxml:literal name="l1" value="a1" />
359+
<cgxml:literal name="l1" value="a2" />
360+
<cgxml:literal name="l2" value="b" />
361+
</cgxml:entity>
362+
</cgxml:record>
363+
<cgxml:record id="2x">
364+
<cgxml:entity name="entity:d,c">
365+
<cgxml:literal name="l2" value="c" />
366+
<cgxml:literal name="l1" value="d" />
367+
</cgxml:entity>
368+
</cgxml:record>
369+
</cgxml:records>
370+
</cgxml:cgxml>
371+
</result>
372+
</test-case>
373+
265374
</metamorph-test>

0 commit comments

Comments
 (0)