diff --git a/metafix/src/main/java/org/metafacture/metafix/FixPath.java b/metafix/src/main/java/org/metafacture/metafix/FixPath.java index 084bdb3c..fe3e086a 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixPath.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixPath.java @@ -54,29 +54,38 @@ public Value findIn(final Hash hash) { final String currentSegment = path[0]; final String[] remainingPath = tail(path); + final Value result; + if (currentSegment.equals(ASTERISK)) { // TODO: search in all elements of value.asHash()? - return new FixPath(remainingPath).findIn(hash); + result = new FixPath(remainingPath).findIn(hash); } - final List result = new ArrayList(); - hash.findFields(currentSegment).collect(Collectors.toSet()).forEach(f -> { - final Value value = hash.getField(f); + else if (remainingPath.length == 0) { + result = hash.get(currentSegment); + } + else { + final List list = new ArrayList<>(); - if (value != null) { - if (remainingPath.length == 0) { - result.add(value); - } - else { - value.matchType() - .ifArray(a -> result.add(new FixPath(remainingPath).findIn(a))) - .ifHash(h -> result.add(new FixPath(remainingPath).findIn(h))) - .orElseThrow(); + hash.findFields(currentSegment).forEach(f -> { + final Value value = hash.getField(f); + + if (value != null) { + if (remainingPath.length == 0) { + list.add(value); + } + else { + value.matchType() + .ifArray(a -> list.add(new FixPath(remainingPath).findIn(a))) + .ifHash(h -> list.add(new FixPath(remainingPath).findIn(h))) + .orElseThrow(); + } } - } - }); - return path.length == 1 ? hash.get(currentSegment) : - result.size() == 1 ? result.get(0) : - result.size() == 0 ? null : new Value(result); + }); + + result = Value.fromList(list); + } + + return result; } /*package-private*/ Value findIn(final Array array) { diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 3b05af9d..22a54b7f 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -204,6 +204,14 @@ public Value asList(final Consumer consumer) { } } + /*package-private*/ static Value fromList(final List list) { + list.removeIf(Objects::isNull); + + return list.isEmpty() ? null : list.size() == 1 ? list.get(0) : newArray(a -> list.forEach(v -> v.matchType() + .ifArray(b -> b.forEach(a::add)) + .orElse(a::add))); + } + public TypeMatcher matchType() { return new TypeMatcher(this); } @@ -522,10 +530,7 @@ public void replace(final String field, final Value value) { */ public Value get(final String field) { // TODO: special treatment (only) for exact matches? - final List list = findFields(field).map(this::getField).collect(Collectors.toList()); - return list.isEmpty() ? null : list.size() == 1 ? list.get(0) : newArray(a -> list.forEach(v -> v.matchType() - .ifArray(b -> b.forEach(a::add)) - .orElse(a::add))); + return fromList(findFields(field).map(this::getField).collect(Collectors.toList())); } public Value getField(final String field) { diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java index 59170088..87eb89f5 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java @@ -615,6 +615,58 @@ public void shouldIterateOverListWithWildcard() { shouldIterateOverList("n?me", 3); } + private void shouldIterateOverListOfHashes(final String path, final int expectedCount) { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "do list(path: '" + path + "', 'var': '$i')", + " add_field('trace', 'true')", + "end", + "retain('trace')" + ), + i -> { + i.startRecord("1"); + i.startEntity("name"); + i.literal("value", "Mary"); + i.endEntity(); + i.startEntity("name"); + i.literal("value", "University"); + i.endEntity(); + i.startEntity("nome"); + i.literal("value", "Max"); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + f.apply(expectedCount).literal("trace", "true"); + o.get().endRecord(); + } + ); + } + + @Test + public void shouldIterateOverListOfHashes() { + shouldIterateOverListOfHashes("name.value", 2); + } + + @Test + // See https://github.com/metafacture/metafacture-fix/issues/119 + public void shouldIterateOverListOfHashesWithCharacterClass() { + shouldIterateOverListOfHashes("n[ao]me.value", 3); + } + + @Test + // See https://github.com/metafacture/metafacture-fix/issues/119 + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/143") + public void shouldIterateOverListOfHashesWithAlternation() { + shouldIterateOverListOfHashes("name.value|nome.value", 3); + } + + @Test + // See https://github.com/metafacture/metafacture-fix/issues/119 + public void shouldIterateOverListOfHashesWithWildcard() { + shouldIterateOverListOfHashes("n?me.value", 3); + } + @Test // checkstyle-disable-line JavaNCSS // See https://github.com/metafacture/metafacture-fix/issues/119 public void shouldPerformComplexOperationWithPathWildcard() {