Skip to content

Commit

Permalink
Merge pull request #73 from cboehme/range-expander-collector
Browse files Browse the repository at this point in the history
Added a metamorph collector to output ranges.
  • Loading branch information
Markus M. Geipel committed May 10, 2013
2 parents 0b53726 + 3551526 commit a62d463
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 4 deletions.
71 changes: 71 additions & 0 deletions src/main/java/org/culturegraph/mf/morph/collectors/Range.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2013 Deutsche Nationalbibliothek
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.culturegraph.mf.morph.collectors;

import java.util.SortedSet;
import java.util.TreeSet;

import org.culturegraph.mf.morph.Metamorph;
import org.culturegraph.mf.morph.NamedValueSource;


/**
* Corresponds to the <code>&lt;range&gt;</code> tag.
*
* @author Christoph Böhme
*/
public final class Range extends AbstractCollect {
private final SortedSet<Integer> values = new TreeSet<Integer>();

private Integer first;

public Range(final Metamorph metamorph) {
super(metamorph);
setNamedValueReceiver(metamorph);
}

@Override
protected void emit() {
for (final Integer i: values) {
getNamedValueReceiver().receive(getName(), i.toString(), this, getRecordCount(), getEntityCount());
}
}

@Override
protected boolean isComplete() {
return false;
}

@Override
protected void receive(final String name, final String value, final NamedValueSource source) {
if (first == null) {
first = Integer.valueOf(value);
} else {
final int last = Integer.valueOf(value).intValue();
for (int i = first.intValue(); i <= last; ++i) {
values.add(Integer.valueOf(i));
}
first = null;
}
}

@Override
protected void clear() {
values.clear();
first = null;
}

}
3 changes: 2 additions & 1 deletion src/main/resources/morph-collectors.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ group org.culturegraph.mf.morph.collectors.Group
entity org.culturegraph.mf.morph.collectors.Entity
concat org.culturegraph.mf.morph.collectors.Concat
tuples org.culturegraph.mf.morph.collectors.Tuples
square org.culturegraph.mf.morph.collectors.Square
square org.culturegraph.mf.morph.collectors.Square
range org.culturegraph.mf.morph.collectors.Range
17 changes: 15 additions & 2 deletions src/main/resources/schemata/metamorph.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@
</element>

<element name="entity">
<annotation><documentation>Create an entity</documentation></annotation>
<annotation><documentation>Create an entity</documentation></annotation>
<complexType>
<choice minOccurs="1" maxOccurs="unbounded">
<element ref="tns:entity-name" minOccurs="0" maxOccurs="1" />
Expand All @@ -284,7 +284,19 @@
</complexType>
</element>


<element name="range">
<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>
<complexType>
<sequence>
<group ref="tns:literal-rule" minOccurs="1" maxOccurs="unbounded" />
<element ref="tns:postprocess" minOccurs="0" maxOccurs="1" />
</sequence>
<attribute name="name" type="string" use="required" />
<attribute name="reset" type="boolean" use="optional" default="false" />
<attribute name="sameEntity" type="boolean" use="optional" default="false" />
<attribute name="flushWith" type="string" use="optional" default="record"/>
</complexType>
</element>

<element name="data">
<annotation><documentation>Used to receive literals</documentation></annotation>
Expand Down Expand Up @@ -441,6 +453,7 @@
<element ref="tns:concat" />
<element ref="tns:square" />
<element ref="tns:tuples" />
<element ref="tns:range" />
</choice>
</group>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
*/
@RunWith(TestSuite.class)
@TestDefinitions({ "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml" })
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml", "RangeTest.xml" })
public final class CollectorTest {/* bind to xml test */
}
164 changes: 164 additions & 0 deletions src/test/java/org/culturegraph/mf/morph/collectors/RangeTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<metamorph-test version="1.0"
xmlns="http://www.culturegraph.org/metamorph-test" xmlns:mm="http://www.culturegraph.org/metamorph"
xmlns:cgxml="http://www.culturegraph.org/cgxml">

<test-case name="should output all numbers between first and last (including first and last)">
<input type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="first" value="1789" />
<cgxml:literal name="last" value="1794" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</input>

<transformation type="text/x-metamorph+xml">
<mm:metamorph version="1">
<mm:rules>
<mm:range name="range" flushWith="record">
<mm:data source="first" />
<mm:data source="last" />
</mm:range>
</mm:rules>
</mm:metamorph>
</transformation>

<result type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="range" value="1789" />
<cgxml:literal name="range" value="1790" />
<cgxml:literal name="range" value="1791" />
<cgxml:literal name="range" value="1792" />
<cgxml:literal name="range" value="1793" />
<cgxml:literal name="range" value="1794" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</result>
</test-case>

<test-case name="should output first if last equals first">
<input type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="first" value="1989" />
<cgxml:literal name="last" value="1989" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</input>

<transformation type="text/x-metamorph+xml">
<mm:metamorph version="1">
<mm:rules>
<mm:range name="range" flushWith="record">
<mm:data source="first" />
<mm:data source="last" />
</mm:range>
</mm:rules>
</mm:metamorph>
</transformation>

<result type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="range" value="1989" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</result>
</test-case>

<test-case name="should output multiple ranges">
<input type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="first" value="1789" />
<cgxml:literal name="last" value="1792" />
<cgxml:literal name="first" value="1794" />
<cgxml:literal name="last" value="1799" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</input>

<transformation type="text/x-metamorph+xml">
<mm:metamorph version="1">
<mm:rules>
<mm:range name="range" flushWith="record">
<mm:data source="first" />
<mm:data source="last" />
</mm:range>
</mm:rules>
</mm:metamorph>
</transformation>

<result type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="range" value="1789" />
<cgxml:literal name="range" value="1790" />
<cgxml:literal name="range" value="1791" />
<cgxml:literal name="range" value="1792" />

<cgxml:literal name="range" value="1794" />
<cgxml:literal name="range" value="1795" />
<cgxml:literal name="range" value="1796" />
<cgxml:literal name="range" value="1797" />
<cgxml:literal name="range" value="1798" />
<cgxml:literal name="range" value="1799" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</result>
</test-case>

<test-case name="should remove duplicate numbers from overlapping ranges">
<input type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="first" value="1789" />
<cgxml:literal name="last" value="1792" />
<cgxml:literal name="first" value="1790" />
<cgxml:literal name="last" value="1791" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</input>

<transformation type="text/x-metamorph+xml">
<mm:metamorph version="1">
<mm:rules>
<mm:range name="range" flushWith="record">
<mm:data source="first" />
<mm:data source="last" />
</mm:range>
</mm:rules>
</mm:metamorph>
</transformation>

<result type="text/x-cg+xml">
<cgxml:cgxml version="1.0">
<cgxml:records>
<cgxml:record id="1">
<cgxml:literal name="range" value="1789" />
<cgxml:literal name="range" value="1790" />
<cgxml:literal name="range" value="1791" />
<cgxml:literal name="range" value="1792" />
</cgxml:record>
</cgxml:records>
</cgxml:cgxml>
</result>
</test-case>

</metamorph-test>

0 comments on commit a62d463

Please sign in to comment.