(root)/u/maxc/main/mkgmap-2_filter_not-contained.patch - Rev 3429
Rev 3426 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
Index: doc/styles/rules-filters.txt
===================================================================
--- doc/styles/rules-filters.txt (revision 3424)
+++ doc/styles/rules-filters.txt (working copy)
@@ -129,6 +129,28 @@
`${name\|substring:2:5}`
If the "name" was "Dorset Lane", then the result is "rse". If there is just the one number,
then the substring starts from that character until the end of the string.
+
+| not-contained | `separator tag` |
+Used to check for duplicate values. If the value of this tag is contained in the list being
+the value of the tag named as the argument to +not-contained+, then value
+of this tag is set to undefined.
+
+....
+type=route & route=bus & ref=* {
+ apply {
+ set route_ref='$(route_ref),${ref|not-contained:,:route_ref}' | '$(route_ref)' | '${ref}';
+ }
+}
+....
+
+Here, +ref+ value is only added to +route_ref+ when it is not already contained in that list
+(with separator ','). Otherwise the value is unchanged.
+This helps to get correct labeling (no duplicates) for public transport lines where there can be multiple relations
+with the same +ref+ attribute (e.g. one for the forward and one for the backward direction).
+
+For example, if +route_ref+ was already "1,2,150" and +ref+ would again be "150",
+this value would not be added to the list as it is already there.
+In contrast, +ref+ equal to "229" would be added, so after that +route_ref+ would have the value "1,2,150,229"
|=====
=== Symbol codes
Index: src/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilter.java (revision 0)
+++ src/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilter.java (revision 0)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015.
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License version 3 or version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.regex.Pattern;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.TagDict;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+/**
+ * This can be used to filter out redundant values.<br>
+ * <br>
+ * The filter checks whether the value is contained within another tag's value. If so, a
+ * null string is returned.<br>
+ * <br>
+ * Another tag should consist of values separated by a delimiter (semicolon ';' by
+ * default).<br>
+ * <br>
+ * Example: after<br>
+ * <code>set tag='Aa#Bb#Cc';</code><br>
+ * <code>set tag2='Ax|not-contained:#:tag';</code> would set the tag 'tag2' to the value
+ * 'Ax', whereas<br>
+ * <code>set tag3='Aa|not-contained:#:tag';</code> would set leave the tag 'tag3'
+ * undefined.
+ *
+ * @author Maxim Duester
+ */
+public class NotContainedFilter extends ValueFilter {
+ private String separator;
+ private short tagKey;
+
+ public NotContainedFilter(String arg) {
+ String[] temp = arg.split(":");
+
+ if (temp.length < 2 || temp[1].isEmpty())
+ throw new SyntaxException(
+ "Missing tag to compare in style not-contained command: " + arg);
+
+ // set the separator (default to ;)
+ if (temp[0].length() > 0)
+ separator = temp[0];
+ else
+ separator = ";";
+ // set the tag short value
+ tagKey = TagDict.getInstance().xlate(temp[1]);
+ }
+
+ public String doFilter(String value, Element el) {
+ if (value == null)
+ return null;
+
+ String tagValue = el.getTag(tagKey);
+ if (tagValue == null)
+ return value;
+
+ // split uses a regex we need to replace special characters
+ String[] temp = tagValue.split(Pattern.quote(separator));
+
+ for (String s : temp)
+ if (s.equals(value))
+ return null;
+
+ // nothing found => value not in tag's value
+ return value;
+ }
+}
Index: src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java (revision 3424)
+++ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java (working copy)
@@ -236,6 +236,9 @@
case "country-ISO":
item.addFilter(new CountryISOFilter());
break;
+ case "not-contained":
+ item.addFilter(new NotContainedFilter(arg));
+ break;
default:
throw new SyntaxException(String.format("Unknown filter '%s'", cmd));
}
Index: test/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilterTest.java
===================================================================
--- test/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilterTest.java (revision 0)
+++ test/uk/me/parabola/mkgmap/osmstyle/actions/NotContainedFilterTest.java (revision 0)
@@ -0,0 +1,83 @@
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+/**
+ * @author Maxim Duester
+ *
+ */
+public class NotContainedFilterTest {
+
+ @Test(expected = SyntaxException.class)
+ public void testNoArg() {
+ NotContainedFilter filter = new NotContainedFilter("");
+ filter.doFilter("x", null);
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testOneArg() {
+ NotContainedFilter filter = new NotContainedFilter(";");
+ filter.doFilter("x", null);
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void test2ndArgMissing() {
+ NotContainedFilter filter = new NotContainedFilter(":");
+ filter.doFilter("x", null);
+ }
+
+ @Test
+ public void test2ndArgNotContained() {
+ NotContainedFilter filter = new NotContainedFilter(";:ref");
+ Element el = stdElement();
+ String s = filter.doFilter("aa", el);
+ assertEquals(s, "aa");
+ }
+
+ @Test
+ public void test2ndArgContained() {
+ NotContainedFilter filter = new NotContainedFilter(":ref");
+ Element el = stdElement();
+ String s = filter.doFilter("x", el);
+ assertNull(s);
+ }
+
+ @Test
+ public void testNonDefaultDelimiterNotContained() {
+ NotContainedFilter filter = new NotContainedFilter("#:ref");
+ Element el = stdElement();
+ String s = filter.doFilter("x", el);
+ assertEquals(s, "x");
+ }
+
+ @Test
+ public void testNonDefaultDelimiterContained() {
+ NotContainedFilter filter = new NotContainedFilter("#:test");
+ Element el = stdElement();
+ el.addTag("test", "Aa#Bb#Cc#Dd");
+ String s = filter.doFilter("Cc", el);
+ assertNull(s);
+ }
+
+ @Test
+ public void testMissingTag(){
+ NotContainedFilter filter=new NotContainedFilter(":sometag");
+ Element el = stdElement();
+ String s=filter.doFilter("x", el);
+ assertEquals(s, "x");
+ }
+
+ private Element stdElement() {
+ Element el1 = new Way(1);
+ el1.addTag("ref", "x;y;z");
+ return el1;
+ }
+
+}