Changeset 4546 in josm


Ignore:
Timestamp:
2011-10-29T09:01:30+02:00 (8 years ago)
Author:
jttt
Message:

Extend name templates with context switch - possibility to use tags of referenced primitive when constructing primitive name

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r4377 r4546  
    6969        protected boolean existsMatch(Collection<? extends OsmPrimitive> primitives) {
    7070            for (OsmPrimitive p : primitives) {
    71                 if (match(p)) {
     71                if (match(p))
    7272                    return true;
    73                 }
    7473            }
    7574            return false;
     
    8180        protected boolean forallMatch(Collection<? extends OsmPrimitive> primitives) {
    8281            for (OsmPrimitive p : primitives) {
    83                 if (!match(p)) {
     82                if (!match(p))
    8483                    return false;
    85                 }
    8684            }
    8785            return true;
     
    110108        }
    111109        @Override public String toString() {return "!"+match;}
     110        public Match getMatch() {
     111            return match;
     112        }
    112113    }
    113114
     
    130131    }
    131132
    132     private static class And extends Match {
    133         private Match lhs;
    134         private Match rhs;
     133    public static class And extends Match {
     134        private final Match lhs;
     135        private final Match rhs;
    135136        public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
    136137        @Override public boolean match(OsmPrimitive osm) {
     
    138139        }
    139140        @Override public String toString() {return lhs+" && "+rhs;}
    140     }
    141 
    142     private static class Or extends Match {
    143         private Match lhs;
    144         private Match rhs;
     141        public Match getLhs() {
     142            return lhs;
     143        }
     144        public Match getRhs() {
     145            return rhs;
     146        }
     147    }
     148
     149    public static class Or extends Match {
     150        private final Match lhs;
     151        private final Match rhs;
    145152        public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
    146153        @Override public boolean match(OsmPrimitive osm) {
     
    148155        }
    149156        @Override public String toString() {return lhs+" || "+rhs;}
     157        public Match getLhs() {
     158            return lhs;
     159        }
     160        public Match getRhs() {
     161            return rhs;
     162        }
    150163    }
    151164
     
    552565        public boolean match(OsmPrimitive osm) {
    553566            Integer count = getCount(osm);
    554             if (count == null) {
     567            if (count == null)
    555568                return false;
    556             } else {
     569            else
    557570                return (count >= minCount) && (count <= maxCount);
    558             }
    559571        }
    560572
     
    575587        @Override
    576588        protected Integer getCount(OsmPrimitive osm) {
    577             if (!(osm instanceof Way)) {
     589            if (!(osm instanceof Way))
    578590                return null;
    579             } else {
     591            else
    580592                return ((Way) osm).getNodesCount();
    581             }
    582593        }
    583594
     
    649660    }
    650661
    651     private static class Parent extends Match {
    652         private Match child;
    653         public Parent(Match m) { child = m; }
     662    public static class Parent extends Match {
     663        private final Match child;
     664        public Parent(Match m) {
     665            if (m == null) {
     666                // "parent" (null) should mean the same as "parent()"
     667                // (Always). I.e. match everything
     668                child = new Always();
     669            } else {
     670                child = m;
     671            }
     672        }
    654673        @Override public boolean match(OsmPrimitive osm) {
    655674            boolean isParent = false;
    656 
    657             // "parent" (null) should mean the same as "parent()"
    658             // (Always). I.e. match everything
    659             if (child == null) {
    660                 child = new Always();
    661             }
    662675
    663676            if (osm instanceof Way) {
     
    673686        }
    674687        @Override public String toString() {return "parent(" + child + ")";}
    675     }
    676 
    677     private static class Child extends Match {
     688        public Match getChild() {
     689            return child;
     690        }
     691    }
     692
     693    public static class Child extends Match {
    678694        private final Match parent;
    679695
     
    696712        }
    697713        @Override public String toString() {return "child(" + parent + ")";}
    698     }
    699    
     714
     715        public Match getParent() {
     716            return parent;
     717        }
     718    }
     719
    700720    /**
    701721     * Matches on the area of a closed way.
    702      * 
     722     *
    703723     * @author Ole Jørgen Brønner
    704724     */
     
    711731        @Override
    712732        protected Integer getCount(OsmPrimitive osm) {
    713             if (!(osm instanceof Way && ((Way) osm).isClosed())) {
     733            if (!(osm instanceof Way && ((Way) osm).isClosed()))
    714734                return null;
    715             }
    716735            Way way = (Way) osm;
    717736            return (int) Geometry.closedWayArea(way);
     
    743762        @Override
    744763        public boolean match(OsmPrimitive osm) {
    745             if (!osm.isUsable()) {
     764            if (!osm.isUsable())
    746765                return false;
    747             } else if (osm instanceof Node) {
     766            else if (osm instanceof Node)
    748767                return bounds.contains(((Node) osm).getCoor());
    749             } else if (osm instanceof Way) {
     768            else if (osm instanceof Way) {
    750769                Collection<Node> nodes = ((Way) osm).getNodes();
    751770                return all ? forallMatch(nodes) : existsMatch(nodes);
     
    753772                Collection<OsmPrimitive> primitives = ((Relation) osm).getMemberPrimitives();
    754773                return all ? forallMatch(primitives) : existsMatch(primitives);
    755             } else {
     774            } else
    756775                return false;
    757             }
    758776        }
    759777    }
     
    799817
    800818    public static Match compile(String searchStr, boolean caseSensitive, boolean regexSearch)
    801     throws ParseError {
     819            throws ParseError {
    802820        return new SearchCompiler(caseSensitive, regexSearch,
    803821                new PushbackTokenizer(
  • trunk/src/org/openstreetmap/josm/tools/template_engine/ParseError.java

    r4282 r4546  
    2121    }
    2222
    23     public ParseError(org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) {
    24         super(tr("Error while parsing search expression"), e);
     23    public ParseError(int position, org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) {
     24        super(tr("Error while parsing search expression on position {0}", position), e);
     25        unexpectedToken = null;
     26    }
     27
     28    public ParseError(String message) {
     29        super(message);
    2530        unexpectedToken = null;
    2631    }
     
    2934        return unexpectedToken;
    3035    }
     36
     37    public static ParseError unexpectedChar(char expected, char found, int position) {
     38        return new ParseError(tr("Unexpected char on {0}. Expected {1} found {2}", position, expected, found));
     39    }
    3140}
  • trunk/src/org/openstreetmap/josm/tools/template_engine/TemplateParser.java

    r4282 r4546  
    22package org.openstreetmap.josm.tools.template_engine;
    33
     4
     5import static org.openstreetmap.josm.tools.I18n.tr;
    46
    57import java.util.ArrayList;
     
    911
    1012import org.openstreetmap.josm.actions.search.SearchCompiler;
     13import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
    1114import org.openstreetmap.josm.tools.template_engine.Tokenizer.Token;
    1215import org.openstreetmap.josm.tools.template_engine.Tokenizer.TokenType;
     
    4245            if (token.getType() == TokenType.CONDITION_START) {
    4346                templateEntry = parseCondition();
     47            } else if (token.getType() == TokenType.CONTEXT_SWITCH_START) {
     48                templateEntry = parseContextSwitch();
    4449            } else if (token.getType() == TokenType.VARIABLE_START) {
    4550                templateEntry = parseVariable();
     
    6368    }
    6469
    65     private void skipWhitespace() {
     70    private void skipWhitespace() throws ParseError {
    6671        Token token = tokenizer.lookAhead();
    6772        if (token.getType() == TokenType.TEXT && token.getText().trim().isEmpty()) {
     
    7681
    7782            TemplateEntry condition;
    78             String searchExpression = tokenizer.skip('\'');
     83            Token searchExpression = tokenizer.skip('\'');
    7984            check(TokenType.APOSTROPHE);
    8085            condition = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS);
    8186            check(TokenType.APOSTROPHE);
    82             if (searchExpression.trim().isEmpty()) {
     87            if (searchExpression.getText().trim().isEmpty()) {
    8388                result.getEntries().add(condition);
    8489            } else {
    8590                try {
    86                     result.getEntries().add(new SearchExpressionCondition(SearchCompiler.compile(searchExpression, false, false), condition));
     91                    result.getEntries().add(new SearchExpressionCondition(SearchCompiler.compile(searchExpression.getText(), false, false), condition));
    8792                } catch (org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) {
    88                     throw new ParseError(e);
     93                    throw new ParseError(searchExpression.getPosition(), e);
    8994                }
    9095            }
     
    101106    }
    102107
     108    private TemplateEntry parseContextSwitch() throws ParseError {
     109
     110        check(TokenType.CONTEXT_SWITCH_START);
     111        Token searchExpression = tokenizer.skip('\'');
     112        check(TokenType.APOSTROPHE);
     113        TemplateEntry template = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS);
     114        check(TokenType.APOSTROPHE);
     115        ContextSwitchTemplate result;
     116        if (searchExpression.getText().trim().isEmpty())
     117            throw new ParseError(tr("Expected search expression"));
     118        else {
     119            try {
     120                Match match = SearchCompiler.compile(searchExpression.getText(), false, false);
     121                result = new ContextSwitchTemplate(match, template, searchExpression.getPosition());
     122            } catch (org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) {
     123                throw new ParseError(searchExpression.getPosition(), e);
     124            }
     125        }
     126        skipWhitespace();
     127        check(TokenType.END);
     128        return result;
     129    }
     130
    103131}
  • trunk/src/org/openstreetmap/josm/tools/template_engine/Tokenizer.java

    r4282 r4546  
    4040    }
    4141
    42     public enum TokenType { CONDITION_START, VARIABLE_START, END, PIPE, APOSTROPHE, TEXT, EOF }
     42    public enum TokenType { CONDITION_START, VARIABLE_START, CONTEXT_SWITCH_START, END, PIPE, APOSTROPHE, TEXT, EOF }
    4343
    4444    private final List<Character> specialCharaters = Arrays.asList(new Character[] {'$', '?', '{', '}', '|', '\''});
     
    6464    }
    6565
    66     public Token nextToken() {
     66    public Token nextToken() throws ParseError {
    6767        if (currentToken != null) {
    6868            Token result = currentToken;
     
    7979            getChar();
    8080            return new Token(TokenType.VARIABLE_START, position);
    81 
    8281        case '?':
    8382            getChar();
     
    8685                return new Token(TokenType.CONDITION_START, position);
    8786            } else
    88                 throw new AssertionError();
     87                throw ParseError.unexpectedChar('{', (char)c, position);
     88        case '!':
     89            getChar();
     90            if (c == '{') {
     91                getChar();
     92                return new Token(TokenType.CONTEXT_SWITCH_START, position);
     93            } else
     94                throw ParseError.unexpectedChar('{', (char)c, position);
    8995        case '}':
    9096            getChar();
     
    111117    }
    112118
    113     public Token lookAhead() {
     119    public Token lookAhead() throws ParseError {
    114120        if (currentToken == null) {
    115121            currentToken = nextToken();
     
    118124    }
    119125
    120     public String skip(char lastChar) {
     126    public Token skip(char lastChar) {
    121127        currentToken = null;
     128        int position = index;
    122129        StringBuilder result = new StringBuilder();
    123130        while (c != lastChar && c != -1) {
     
    128135            getChar();
    129136        }
    130         return result.toString();
     137        return new Token(TokenType.TEXT, position, result.toString());
    131138    }
    132139
  • trunk/test/unit/org/openstreetmap/josm/tools/template_engine/TemplateEngineTest.java

    r4431 r4546  
    1313import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
    1414import org.openstreetmap.josm.data.Preferences;
     15import org.openstreetmap.josm.data.osm.DatasetFactory;
     16import org.openstreetmap.josm.data.osm.Node;
    1517import org.openstreetmap.josm.data.osm.Relation;
     18import org.openstreetmap.josm.data.osm.RelationMember;
    1619import org.unitils.reflectionassert.ReflectionAssert;
    1720
     
    150153        templateEntry.appendText(sb, dataProvider);
    151154        Assert.assertEquals("waypointNameulocalNameuspecialKey", sb.toString());
    152 
    153     }
    154 
     155    }
     156
     157    @Test
     158    public void testSearchExpression() throws Exception {
     159        Match match = compile("(parent type=type1 type=parent1) | (parent type=type2 type=parent2)");
     160        //"parent(type=type1,type=parent1) | (parent(type=type2,type=parent2)"
     161        //TODO
     162    }
     163
     164    @Test
     165    public void testSwitchContext() throws Exception {
     166        TemplateParser parser = new TemplateParser("!{parent() type=parent2 '{name}'}");
     167        DatasetFactory ds = new DatasetFactory();
     168        Relation parent1 = ds.addRelation(1);
     169        parent1.put("type", "parent1");
     170        parent1.put("name", "name_parent1");
     171        Relation parent2 = ds.addRelation(2);
     172        parent2.put("type", "parent2");
     173        parent2.put("name", "name_parent2");
     174        Node child = ds.addNode(1);
     175        parent1.addMember(new RelationMember("", child));
     176        parent2.addMember(new RelationMember("", child));
     177
     178        StringBuilder sb = new StringBuilder();
     179        TemplateEntry entry = parser.parse();
     180        entry.appendText(sb, child);
     181
     182        Assert.assertEquals("name_parent2", sb.toString());
     183    }
     184
     185    @Test
     186    public void testSetOr() throws ParseError {
     187        TemplateParser parser = new TemplateParser("!{(parent(type=type1) type=parent1) | (parent type=type2 type=parent2) '{name}'}");
     188        DatasetFactory ds = new DatasetFactory();
     189        Relation parent1 = ds.addRelation(1);
     190        parent1.put("type", "parent1");
     191        parent1.put("name", "name_parent1");
     192        Relation parent2 = ds.addRelation(2);
     193        parent2.put("type", "parent2");
     194        parent2.put("name", "name_parent2");
     195        Node child1 = ds.addNode(1);
     196        child1.put("type", "type1");
     197        parent1.addMember(new RelationMember("", child1));
     198        parent2.addMember(new RelationMember("", child1));
     199        Node child2 = ds.addNode(2);
     200        child2.put("type", "type2");
     201        parent1.addMember(new RelationMember("", child2));
     202        parent2.addMember(new RelationMember("", child2));
     203
     204
     205        StringBuilder sb = new StringBuilder();
     206        TemplateEntry entry = parser.parse();
     207        entry.appendText(sb, child1);
     208        entry.appendText(sb, child2);
     209
     210        Assert.assertEquals("name_parent1name_parent2", sb.toString());
     211    }
     212
     213    @Test
     214    public void testMultilevel() throws ParseError {
     215        TemplateParser parser = new TemplateParser("!{(parent(parent(type=type1)) type=grandparent) | (parent type=type2 type=parent2) '{name}'}");
     216        DatasetFactory ds = new DatasetFactory();
     217        Relation parent1 = ds.addRelation(1);
     218        parent1.put("type", "parent1");
     219        parent1.put("name", "name_parent1");
     220        Relation parent2 = ds.addRelation(2);
     221        parent2.put("type", "parent2");
     222        parent2.put("name", "name_parent2");
     223        Node child1 = ds.addNode(1);
     224        child1.put("type", "type1");
     225        parent1.addMember(new RelationMember("", child1));
     226        parent2.addMember(new RelationMember("", child1));
     227        Node child2 = ds.addNode(2);
     228        child2.put("type", "type2");
     229        parent1.addMember(new RelationMember("", child2));
     230        parent2.addMember(new RelationMember("", child2));
     231        Relation grandParent = ds.addRelation(3);
     232        grandParent.put("type", "grandparent");
     233        grandParent.put("name", "grandparent_name");
     234        grandParent.addMember(new RelationMember("", parent1));
     235
     236
     237        StringBuilder sb = new StringBuilder();
     238        TemplateEntry entry = parser.parse();
     239        entry.appendText(sb, child1);
     240        entry.appendText(sb, child2);
     241
     242        Assert.assertEquals("grandparent_namename_parent2", sb.toString());
     243    }
     244
     245    @Test(expected=ParseError.class)
     246    public void testErrorsNot() throws ParseError {
     247        TemplateParser parser = new TemplateParser("!{-parent() '{name}'}");
     248        parser.parse();
     249    }
     250
     251    @Test(expected=ParseError.class)
     252    public void testErrorOr() throws ParseError {
     253        TemplateParser parser = new TemplateParser("!{parent() | type=type1 '{name}'}");
     254        parser.parse();
     255    }
     256
     257    @Test
     258    public void testChild() throws ParseError {
     259        TemplateParser parser = new TemplateParser("!{((child(type=type1) type=child1) | (child type=type2 type=child2)) type=child2 '{name}'}");
     260        DatasetFactory ds = new DatasetFactory();
     261        Relation parent1 = ds.addRelation(1);
     262        parent1.put("type", "type1");
     263        Relation parent2 = ds.addRelation(2);
     264        parent2.put("type", "type2");
     265        Node child1 = ds.addNode(1);
     266        child1.put("type", "child1");
     267        child1.put("name", "child1");
     268        parent1.addMember(new RelationMember("", child1));
     269        parent2.addMember(new RelationMember("", child1));
     270        Node child2 = ds.addNode(2);
     271        child2.put("type", "child2");
     272        child2.put("name", "child2");
     273        parent1.addMember(new RelationMember("", child2));
     274        parent2.addMember(new RelationMember("", child2));
     275
     276
     277        StringBuilder sb = new StringBuilder();
     278        TemplateEntry entry = parser.parse();
     279        entry.appendText(sb, parent2);
     280
     281        Assert.assertEquals("child2", sb.toString());
     282    }
    155283
    156284}
Note: See TracChangeset for help on using the changeset viewer.