Skip to content

Commit 7d1835b

Browse files
committed
Added a <none> statement to metamorph.
The statement implements a logical not-operation. It allows for checking whether none of the statements contained in the <none> statement generated an output. Using the <none> statement negations can be written in a more expressive way than (ab)using the <combine> and <choose> statements allows. By default the <none> statement outputs an unamed literal with "true" as value. However, this can be customized. <none name="MyCustomName" value="none-fired"> <data source="data1" /> <data source="data2" /> </none> The <none> statement supports reset and flushWith. Conflicts: src/test/java/org/culturegraph/mf/morph/collectors/CollectorTest.java
1 parent 994edae commit 7d1835b

File tree

6 files changed

+256
-2
lines changed

6 files changed

+256
-2
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public final void setValue(final String value) {
9595
this.value = value;
9696
}
9797

98-
private void updateCounts(final int currentRecord, final int currentEntity) {
98+
protected final void updateCounts(final int currentRecord, final int currentEntity) {
9999
if (!isSameRecord(currentRecord)) {
100100
clear();
101101
oldRecord = currentRecord;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2013 Christoph Böhme
3+
*
4+
* Licensed under the Apache License, Version 2.0 the "License";
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.culturegraph.mf.morph.collectors;
17+
18+
import org.culturegraph.mf.morph.Metamorph;
19+
import org.culturegraph.mf.morph.NamedValueSource;
20+
import org.culturegraph.mf.util.StringUtil;
21+
22+
/**
23+
* Corresponds to the <code>&lt;none&gt;</code> tag.
24+
*
25+
* @author Christoph Böhme <[email protected]>
26+
*
27+
*/
28+
public final class None extends AbstractCollect {
29+
30+
private static final String DEFAULT_NAME = "";
31+
private static final String DEFAULT_VALUE = "true";
32+
33+
private boolean receivedInput;
34+
private boolean emittedResult;
35+
36+
public None(final Metamorph metamorph) {
37+
super(metamorph);
38+
setNamedValueReceiver(metamorph);
39+
}
40+
41+
@Override
42+
protected void receive(final String name, final String value, final NamedValueSource source) {
43+
receivedInput = true;
44+
}
45+
46+
@Override
47+
protected boolean isComplete() {
48+
return false;
49+
}
50+
51+
@Override
52+
protected void clear() {
53+
receivedInput = false;
54+
emittedResult = false;
55+
}
56+
57+
@Override
58+
protected void emit() {
59+
if (!receivedInput && !emittedResult) {
60+
final String name = StringUtil.fallback(getName(), DEFAULT_NAME);
61+
final String value = StringUtil.fallback(getValue(), DEFAULT_VALUE);
62+
getNamedValueReceiver().receive(name, value, this, getRecordCount(), getEntityCount());
63+
emittedResult = true;
64+
}
65+
}
66+
67+
@Override
68+
public void flush(final int recordCount, final int entityCount) {
69+
updateCounts(recordCount, entityCount);
70+
emit();
71+
if (getReset()) {
72+
clear();
73+
}
74+
}
75+
76+
}

src/main/resources/morph-collectors.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ choose org.culturegraph.mf.morph.collectors.Choose
55
group org.culturegraph.mf.morph.collectors.Group
66
entity org.culturegraph.mf.morph.collectors.Entity
77
concat org.culturegraph.mf.morph.collectors.Concat
8+
none org.culturegraph.mf.morph.collectors.None
89
tuples org.culturegraph.mf.morph.collectors.Tuples
910
square org.culturegraph.mf.morph.collectors.Square
1011
range org.culturegraph.mf.morph.collectors.Range

src/main/resources/schemata/metamorph.xsd

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,25 @@
250250
</complexType>
251251
</element>
252252

253+
<element name="none">
254+
<annotation>
255+
<documentation>Outputs an unnamed literal with "true" as value if none of
256+
the contained statements fires. This is essentially a logical not operation.
257+
The name and value generated by the all-statement can be customised.</documentation>
258+
</annotation>
259+
<complexType>
260+
<sequence>
261+
<group ref="tns:literal-rule" minOccurs="1" maxOccurs="unbounded" />
262+
</sequence>
263+
<attribute name="name" type="string" use="optional" />
264+
<attribute name="value" type="string" use="optional" />
265+
<attribute name="flushWith" type="string" use="optional"
266+
default="record" />
267+
<attribute name="reset" type="boolean" use="optional"
268+
default="false" />
269+
</complexType>
270+
</element>
271+
253272
<element name="combine">
254273
<complexType>
255274
<sequence>
@@ -598,6 +617,7 @@
598617
<element ref="tns:choose" />
599618
<element ref="tns:combine" />
600619
<element ref="tns:concat" />
620+
<element ref="tns:none" />
601621
<element ref="tns:square" />
602622
<element ref="tns:tuples" />
603623
<element ref="tns:range" />

src/test/java/org/culturegraph/mf/morph/collectors/CollectorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* @author Markus Michael Geipel
2525
*/
2626
@RunWith(TestSuite.class)
27-
@TestDefinitions({ "AllTest.xml", "AnyTest.xml", "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
27+
@TestDefinitions({ "AllTest.xml", "AnyTest.xml", "NoneTest.xml", "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
2828
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml", "RangeTest.xml", "EqualsFilterTest.xml" })
2929
public final class CollectorTest {/* bind to xml test */
3030
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<metamorph-test version="1.0"
3+
xmlns="http://www.culturegraph.org/metamorph-test" xmlns:mm="http://www.culturegraph.org/metamorph"
4+
xmlns:cgxml="http://www.culturegraph.org/cgxml">
5+
6+
<test-case name="should fire only if no element fired">
7+
<input type="text/x-cg+xml">
8+
<cgxml:cgxml version="1.0">
9+
<cgxml:records>
10+
<cgxml:record id="1">
11+
<cgxml:literal name="data1" value="A" />
12+
</cgxml:record>
13+
<cgxml:record id="2">
14+
<cgxml:literal name="data2" value="C" />
15+
</cgxml:record>
16+
<cgxml:record id="3">
17+
<cgxml:literal name="data3" value="C" />
18+
</cgxml:record>
19+
</cgxml:records>
20+
</cgxml:cgxml>
21+
</input>
22+
23+
<transformation type="text/x-metamorph+xml">
24+
<mm:metamorph version="1">
25+
<mm:rules>
26+
<mm:none>
27+
<mm:data source="data1" />
28+
<mm:data source="data2" />
29+
</mm:none>
30+
</mm:rules>
31+
</mm:metamorph>
32+
</transformation>
33+
34+
<result type="text/x-cg+xml">
35+
<cgxml:cgxml version="1.0">
36+
<cgxml:records>
37+
<cgxml:record id="1">
38+
</cgxml:record>
39+
<cgxml:record id="2">
40+
</cgxml:record>
41+
<cgxml:record id="3">
42+
<cgxml:literal name="" value="true" />
43+
</cgxml:record>
44+
</cgxml:records>
45+
</cgxml:cgxml>
46+
</result>
47+
</test-case>
48+
49+
<test-case name="should support user-defined name and value">
50+
<input type="text/x-cg+xml">
51+
<cgxml:cgxml version="1.0">
52+
<cgxml:records>
53+
<cgxml:record id="1">
54+
<cgxml:literal name="data3" value="A" />
55+
</cgxml:record>
56+
</cgxml:records>
57+
</cgxml:cgxml>
58+
</input>
59+
60+
<transformation type="text/x-metamorph+xml">
61+
<mm:metamorph version="1">
62+
<mm:rules>
63+
<mm:none name="NONE" value="found none">
64+
<mm:data source="data1" />
65+
<mm:data source="data2" />
66+
</mm:none>
67+
</mm:rules>
68+
</mm:metamorph>
69+
</transformation>
70+
71+
<result type="text/x-cg+xml">
72+
<cgxml:cgxml version="1.0">
73+
<cgxml:records>
74+
<cgxml:record id="1">
75+
<cgxml:literal name="NONE" value="found none" />
76+
</cgxml:record>
77+
</cgxml:records>
78+
</cgxml:cgxml>
79+
</result>
80+
</test-case>
81+
82+
<test-case name="should not fire again if flushed two times and reset is false">
83+
<input type="text/x-cg+xml">
84+
<cgxml:cgxml version="1.0">
85+
<cgxml:records>
86+
<cgxml:record id="1">
87+
<cgxml:entity name="entity">
88+
<cgxml:literal name="data1" value="A" />
89+
</cgxml:entity>
90+
<cgxml:entity name="entity">
91+
<cgxml:literal name="data1" value="A" />
92+
</cgxml:entity>
93+
</cgxml:record>
94+
</cgxml:records>
95+
</cgxml:cgxml>
96+
</input>
97+
98+
<transformation type="text/x-metamorph+xml">
99+
<mm:metamorph version="1">
100+
<mm:rules>
101+
<mm:none flushWith="entity">
102+
<mm:data source="data2" />
103+
</mm:none>
104+
</mm:rules>
105+
</mm:metamorph>
106+
</transformation>
107+
108+
<result type="text/x-cg+xml">
109+
<cgxml:cgxml version="1.0">
110+
<cgxml:records>
111+
<cgxml:record id="1">
112+
<cgxml:literal name="" value="true" />
113+
</cgxml:record>
114+
</cgxml:records>
115+
</cgxml:cgxml>
116+
</result>
117+
</test-case>
118+
119+
<test-case name="should fire again if flushed two times and reset is true">
120+
<input type="text/x-cg+xml">
121+
<cgxml:cgxml version="1.0">
122+
<cgxml:records>
123+
<cgxml:record id="1">
124+
<cgxml:entity name="entity">
125+
<cgxml:literal name="data1" value="A" />
126+
</cgxml:entity>
127+
<cgxml:entity name="entity">
128+
<cgxml:literal name="data1" value="A" />
129+
</cgxml:entity>
130+
</cgxml:record>
131+
</cgxml:records>
132+
</cgxml:cgxml>
133+
</input>
134+
135+
<transformation type="text/x-metamorph+xml">
136+
<mm:metamorph version="1">
137+
<mm:rules>
138+
<mm:none flushWith="entity" reset="true">
139+
<mm:data source="data2" />
140+
</mm:none>
141+
</mm:rules>
142+
</mm:metamorph>
143+
</transformation>
144+
145+
<result type="text/x-cg+xml">
146+
<cgxml:cgxml version="1.0">
147+
<cgxml:records>
148+
<cgxml:record id="1">
149+
<cgxml:literal name="" value="true" />
150+
<cgxml:literal name="" value="true" />
151+
</cgxml:record>
152+
</cgxml:records>
153+
</cgxml:cgxml>
154+
</result>
155+
</test-case>
156+
157+
</metamorph-test>

0 commit comments

Comments
 (0)