diff --git a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java b/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java index f8ccaaf168..365e598f64 100644 --- a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java +++ b/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java @@ -1,12 +1,16 @@ package edu.stanford.nlp.semgraph.semgrex.ssurgeon; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.TreeMap; +import edu.stanford.nlp.ling.CoreAnnotations; import edu.stanford.nlp.ling.CoreLabel; import edu.stanford.nlp.ling.IndexedWord; import edu.stanford.nlp.semgraph.SemanticGraph; import edu.stanford.nlp.semgraph.semgrex.SemgrexMatcher; +import edu.stanford.nlp.trees.ud.CoNLLUUtils; /** * Edit an existing node to have new attributes. @@ -18,17 +22,23 @@ public class EditNode extends SsurgeonEdit { final String nodeName; final Map attributes; + final Map updateMorphoFeatures; - public EditNode(String nodeName, Map attributes) { + public EditNode(String nodeName, Map attributes, String updateMorphoFeatures) { if (nodeName == null) { throw new SsurgeonParseException("Cannot make an EditNode with no nodeName"); } - if (attributes.size() == 0) { - throw new SsurgeonParseException("Cannot make an EditNode with no attributes"); + if (attributes.size() == 0 && updateMorphoFeatures == null) { + throw new SsurgeonParseException("Cannot make an EditNode with no attributes or updated morphological features"); } AddDep.checkIllegalAttributes(attributes); this.nodeName = nodeName; this.attributes = new TreeMap<>(attributes); + if (updateMorphoFeatures != null) { + this.updateMorphoFeatures = CoNLLUUtils.parseFeatures(updateMorphoFeatures); + } else { + this.updateMorphoFeatures = Collections.emptyMap(); + } } @@ -47,9 +57,16 @@ public String toEditString() { buf.append(key); buf.append(" "); buf.append(attributes.get(key)); + // TODO: why the stray quote characters? buf.append("\"\t"); } + if (this.updateMorphoFeatures.size() > 0) { + buf.append(Ssurgeon.UPDATE_MORPHO_FEATURES); + buf.append(" "); + buf.append(CoNLLUUtils.toFeatureString(this.updateMorphoFeatures)); + } + return buf.toString(); } @@ -76,6 +93,21 @@ public boolean evaluate(SemanticGraph sg, SemgrexMatcher sm) { } } + for (String key : updateMorphoFeatures.keySet()) { + HashMap features = word.get(CoreAnnotations.CoNLLUFeats.class); + if (features == null) { + changed = true; + features = new HashMap<>(); + word.set(CoreAnnotations.CoNLLUFeats.class, features); + } + + // this test will catch null, eg not yet assigned, features as well + if (!updateMorphoFeatures.get(key).equals(features.get(key))) { + changed = true; + features.put(key, updateMorphoFeatures.get(key)); + } + } + return changed; } } diff --git a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/Ssurgeon.java b/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/Ssurgeon.java index 393090acf2..29b12c9d6c 100644 --- a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/Ssurgeon.java +++ b/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/Ssurgeon.java @@ -397,6 +397,7 @@ public Collection getResources() { public static final String WEIGHT_ARG = "-weight"; public static final String NAME_ARG = "-name"; public static final String POSITION_ARG = "-position"; + public static final String UPDATE_MORPHO_FEATURES = "-updateMorphoFeatures"; // args for Ssurgeon edits, allowing us to not @@ -422,6 +423,8 @@ protected static class SsurgeonArgs { public String position = null; + public String updateMorphoFeatures = null; + public Map annotations = new TreeMap<>(); } @@ -492,6 +495,9 @@ private static SsurgeonArgs parseArgsBox(String args, Map additi case POSITION_ARG: argsBox.position = argsValue; break; + case UPDATE_MORPHO_FEATURES: + argsBox.updateMorphoFeatures = argsValue; + break; default: String key = argsKey.substring(1); Class> annotation = AnnotationLookup.toCoreKey(key); @@ -557,7 +563,7 @@ public static SsurgeonEdit parseEditLine(String editLine, Map at if (argsBox.nodes.size() != 1) { throw new SsurgeonParseException("Cannot make an EditNode out of " + argsBox.nodes.size() + " nodes. Please use exactly one -node"); } - return new EditNode(argsBox.nodes.get(0), argsBox.annotations); + return new EditNode(argsBox.nodes.get(0), argsBox.annotations, argsBox.updateMorphoFeatures); } else if (command.equalsIgnoreCase(MergeNodes.LABEL)) { if (argsBox.nodes.size() < 2) { throw new SsurgeonParseException("Cannot make a MergeNodes out of fewer than 2 nodes (got " + argsBox.nodes.size() + ")"); diff --git a/src/edu/stanford/nlp/trees/ud/CoNLLUUtils.java b/src/edu/stanford/nlp/trees/ud/CoNLLUUtils.java index a293690638..97d77c2494 100644 --- a/src/edu/stanford/nlp/trees/ud/CoNLLUUtils.java +++ b/src/edu/stanford/nlp/trees/ud/CoNLLUUtils.java @@ -35,7 +35,7 @@ public static HashMap parseFeatures(String featureString) { * * @return The feature string. */ - public static String toFeatureString(HashMap features) { + public static String toFeatureString(Map features) { StringBuilder sb = new StringBuilder(); boolean first = true; if (features != null) {