Skip to content

Commit 3551526

Browse files
committed
Added a metamorph collector to output ranges.
The collector interprets the first literal it receives as a range start and the second as a range end. The values are converted to integers and for each number between the two an additional literal is generated. Usage: <range name="range"> <data source="first" /> <data source="last" /> </range>
1 parent 426d224 commit 3551526

File tree

5 files changed

+253
-4
lines changed

5 files changed

+253
-4
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2013 Deutsche Nationalbibliothek
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 java.util.SortedSet;
19+
import java.util.TreeSet;
20+
21+
import org.culturegraph.mf.morph.Metamorph;
22+
import org.culturegraph.mf.morph.NamedValueSource;
23+
24+
25+
/**
26+
* Corresponds to the <code>&lt;range&gt;</code> tag.
27+
*
28+
* @author Christoph Böhme
29+
*/
30+
public final class Range extends AbstractCollect {
31+
private final SortedSet<Integer> values = new TreeSet<Integer>();
32+
33+
private Integer first;
34+
35+
public Range(final Metamorph metamorph) {
36+
super(metamorph);
37+
setNamedValueReceiver(metamorph);
38+
}
39+
40+
@Override
41+
protected void emit() {
42+
for (final Integer i: values) {
43+
getNamedValueReceiver().receive(getName(), i.toString(), this, getRecordCount(), getEntityCount());
44+
}
45+
}
46+
47+
@Override
48+
protected boolean isComplete() {
49+
return false;
50+
}
51+
52+
@Override
53+
protected void receive(final String name, final String value, final NamedValueSource source) {
54+
if (first == null) {
55+
first = Integer.valueOf(value);
56+
} else {
57+
final int last = Integer.valueOf(value).intValue();
58+
for (int i = first.intValue(); i <= last; ++i) {
59+
values.add(Integer.valueOf(i));
60+
}
61+
first = null;
62+
}
63+
}
64+
65+
@Override
66+
protected void clear() {
67+
values.clear();
68+
first = null;
69+
}
70+
71+
}

src/main/resources/morph-collectors.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ group org.culturegraph.mf.morph.collectors.Group
44
entity org.culturegraph.mf.morph.collectors.Entity
55
concat org.culturegraph.mf.morph.collectors.Concat
66
tuples org.culturegraph.mf.morph.collectors.Tuples
7-
square org.culturegraph.mf.morph.collectors.Square
7+
square org.culturegraph.mf.morph.collectors.Square
8+
range org.culturegraph.mf.morph.collectors.Range

src/main/resources/schemata/metamorph.xsd

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@
266266
</element>
267267

268268
<element name="entity">
269-
<annotation><documentation>Create an entity</documentation></annotation>
269+
<annotation><documentation>Create an entity</documentation></annotation>
270270
<complexType>
271271
<choice minOccurs="1" maxOccurs="unbounded">
272272
<element ref="tns:entity-name" minOccurs="0" maxOccurs="1" />
@@ -284,7 +284,19 @@
284284
</complexType>
285285
</element>
286286

287-
287+
<element name="range">
288+
<annotation><documentation>Interprets pairs of consecutive literals as integer range start and end. For each number between the two an additional literal is generated.</documentation></annotation>
289+
<complexType>
290+
<sequence>
291+
<group ref="tns:literal-rule" minOccurs="1" maxOccurs="unbounded" />
292+
<element ref="tns:postprocess" minOccurs="0" maxOccurs="1" />
293+
</sequence>
294+
<attribute name="name" type="string" use="required" />
295+
<attribute name="reset" type="boolean" use="optional" default="false" />
296+
<attribute name="sameEntity" type="boolean" use="optional" default="false" />
297+
<attribute name="flushWith" type="string" use="optional" default="record"/>
298+
</complexType>
299+
</element>
288300

289301
<element name="data">
290302
<annotation><documentation>Used to receive literals</documentation></annotation>
@@ -441,6 +453,7 @@
441453
<element ref="tns:concat" />
442454
<element ref="tns:square" />
443455
<element ref="tns:tuples" />
456+
<element ref="tns:range" />
444457
</choice>
445458
</group>
446459

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@
2525
*/
2626
@RunWith(TestSuite.class)
2727
@TestDefinitions({ "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
28-
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml" })
28+
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml", "RangeTest.xml" })
2929
public final class CollectorTest {/* bind to xml test */
3030
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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 output all numbers between first and last (including first and last)">
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="first" value="1789" />
12+
<cgxml:literal name="last" value="1794" />
13+
</cgxml:record>
14+
</cgxml:records>
15+
</cgxml:cgxml>
16+
</input>
17+
18+
<transformation type="text/x-metamorph+xml">
19+
<mm:metamorph version="1">
20+
<mm:rules>
21+
<mm:range name="range" flushWith="record">
22+
<mm:data source="first" />
23+
<mm:data source="last" />
24+
</mm:range>
25+
</mm:rules>
26+
</mm:metamorph>
27+
</transformation>
28+
29+
<result type="text/x-cg+xml">
30+
<cgxml:cgxml version="1.0">
31+
<cgxml:records>
32+
<cgxml:record id="1">
33+
<cgxml:literal name="range" value="1789" />
34+
<cgxml:literal name="range" value="1790" />
35+
<cgxml:literal name="range" value="1791" />
36+
<cgxml:literal name="range" value="1792" />
37+
<cgxml:literal name="range" value="1793" />
38+
<cgxml:literal name="range" value="1794" />
39+
</cgxml:record>
40+
</cgxml:records>
41+
</cgxml:cgxml>
42+
</result>
43+
</test-case>
44+
45+
<test-case name="should output first if last equals first">
46+
<input type="text/x-cg+xml">
47+
<cgxml:cgxml version="1.0">
48+
<cgxml:records>
49+
<cgxml:record id="1">
50+
<cgxml:literal name="first" value="1989" />
51+
<cgxml:literal name="last" value="1989" />
52+
</cgxml:record>
53+
</cgxml:records>
54+
</cgxml:cgxml>
55+
</input>
56+
57+
<transformation type="text/x-metamorph+xml">
58+
<mm:metamorph version="1">
59+
<mm:rules>
60+
<mm:range name="range" flushWith="record">
61+
<mm:data source="first" />
62+
<mm:data source="last" />
63+
</mm:range>
64+
</mm:rules>
65+
</mm:metamorph>
66+
</transformation>
67+
68+
<result type="text/x-cg+xml">
69+
<cgxml:cgxml version="1.0">
70+
<cgxml:records>
71+
<cgxml:record id="1">
72+
<cgxml:literal name="range" value="1989" />
73+
</cgxml:record>
74+
</cgxml:records>
75+
</cgxml:cgxml>
76+
</result>
77+
</test-case>
78+
79+
<test-case name="should output multiple ranges">
80+
<input type="text/x-cg+xml">
81+
<cgxml:cgxml version="1.0">
82+
<cgxml:records>
83+
<cgxml:record id="1">
84+
<cgxml:literal name="first" value="1789" />
85+
<cgxml:literal name="last" value="1792" />
86+
<cgxml:literal name="first" value="1794" />
87+
<cgxml:literal name="last" value="1799" />
88+
</cgxml:record>
89+
</cgxml:records>
90+
</cgxml:cgxml>
91+
</input>
92+
93+
<transformation type="text/x-metamorph+xml">
94+
<mm:metamorph version="1">
95+
<mm:rules>
96+
<mm:range name="range" flushWith="record">
97+
<mm:data source="first" />
98+
<mm:data source="last" />
99+
</mm:range>
100+
</mm:rules>
101+
</mm:metamorph>
102+
</transformation>
103+
104+
<result type="text/x-cg+xml">
105+
<cgxml:cgxml version="1.0">
106+
<cgxml:records>
107+
<cgxml:record id="1">
108+
<cgxml:literal name="range" value="1789" />
109+
<cgxml:literal name="range" value="1790" />
110+
<cgxml:literal name="range" value="1791" />
111+
<cgxml:literal name="range" value="1792" />
112+
113+
<cgxml:literal name="range" value="1794" />
114+
<cgxml:literal name="range" value="1795" />
115+
<cgxml:literal name="range" value="1796" />
116+
<cgxml:literal name="range" value="1797" />
117+
<cgxml:literal name="range" value="1798" />
118+
<cgxml:literal name="range" value="1799" />
119+
</cgxml:record>
120+
</cgxml:records>
121+
</cgxml:cgxml>
122+
</result>
123+
</test-case>
124+
125+
<test-case name="should remove duplicate numbers from overlapping ranges">
126+
<input type="text/x-cg+xml">
127+
<cgxml:cgxml version="1.0">
128+
<cgxml:records>
129+
<cgxml:record id="1">
130+
<cgxml:literal name="first" value="1789" />
131+
<cgxml:literal name="last" value="1792" />
132+
<cgxml:literal name="first" value="1790" />
133+
<cgxml:literal name="last" value="1791" />
134+
</cgxml:record>
135+
</cgxml:records>
136+
</cgxml:cgxml>
137+
</input>
138+
139+
<transformation type="text/x-metamorph+xml">
140+
<mm:metamorph version="1">
141+
<mm:rules>
142+
<mm:range name="range" flushWith="record">
143+
<mm:data source="first" />
144+
<mm:data source="last" />
145+
</mm:range>
146+
</mm:rules>
147+
</mm:metamorph>
148+
</transformation>
149+
150+
<result type="text/x-cg+xml">
151+
<cgxml:cgxml version="1.0">
152+
<cgxml:records>
153+
<cgxml:record id="1">
154+
<cgxml:literal name="range" value="1789" />
155+
<cgxml:literal name="range" value="1790" />
156+
<cgxml:literal name="range" value="1791" />
157+
<cgxml:literal name="range" value="1792" />
158+
</cgxml:record>
159+
</cgxml:records>
160+
</cgxml:cgxml>
161+
</result>
162+
</test-case>
163+
164+
</metamorph-test>

0 commit comments

Comments
 (0)