Repository: nifi Updated Branches: refs/heads/master 0bddcfe73 -> 32314d70f
http://git-wip-us.apache.org/repos/asf/nifi/blob/32314d70/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java index 4f9b53d..51aca43 100644 --- a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java +++ b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java @@ -28,6 +28,7 @@ import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.apache.nifi.record.path.exception.RecordPathException; import org.apache.nifi.serialization.SimpleRecordSchema; import org.apache.nifi.serialization.record.DataType; import org.apache.nifi.serialization.record.MapRecord; @@ -45,6 +46,19 @@ public class TestRecordPath { System.out.println(RecordPath.compile("/person[2]")); System.out.println(RecordPath.compile("//person[2]")); System.out.println(RecordPath.compile("/person/child[1]//sibling/name")); + + // contains is a 'filter function' so can be used as the predicate + RecordPath.compile("/name[contains(., 'hello')]"); + + // substring is not a filter function so cannot be used as a predicate + try { + RecordPath.compile("/name[substring(., 1, 2)]"); + } catch (final RecordPathException e) { + // expected + } + + // substring is not a filter function so can be used as *part* of a predicate but not as the entire predicate + RecordPath.compile("/name[substring(., 1, 2) = 'e']"); } @Test @@ -682,7 +696,7 @@ public class TestRecordPath { final FieldValue recordFieldValue = new StandardFieldValue(record, new RecordField("record", RecordFieldType.RECORD.getDataType()), null); - final List<FieldValue> fieldValues = RecordPath.compile("./name").evaluate(recordFieldValue).getSelectedFields().collect(Collectors.toList()); + final List<FieldValue> fieldValues = RecordPath.compile("./name").evaluate(record, recordFieldValue).getSelectedFields().collect(Collectors.toList()); assertEquals(1, fieldValues.size()); final FieldValue fieldValue = fieldValues.get(0); @@ -702,7 +716,7 @@ public class TestRecordPath { final FieldValue recordFieldValue = new StandardFieldValue(record, new RecordField("root", RecordFieldType.RECORD.getRecordDataType(record.getSchema())), null); final FieldValue nameFieldValue = new StandardFieldValue("John Doe", new RecordField("name", RecordFieldType.STRING.getDataType()), recordFieldValue); - final List<FieldValue> fieldValues = RecordPath.compile(".").evaluate(nameFieldValue).getSelectedFields().collect(Collectors.toList()); + final List<FieldValue> fieldValues = RecordPath.compile(".").evaluate(record, nameFieldValue).getSelectedFields().collect(Collectors.toList()); assertEquals(1, fieldValues.size()); final FieldValue fieldValue = fieldValues.get(0); @@ -714,6 +728,277 @@ public class TestRecordPath { assertEquals("Jane Doe", record.getValue("name")); } + @Test + public void testSubstringFunction() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + final FieldValue fieldValue = RecordPath.compile("substring(/name, 0, 4)").evaluate(record).getSelectedFields().findFirst().get(); + assertEquals("John", fieldValue.getValue()); + + assertEquals("John", RecordPath.compile("substring(/name, 0, -5)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("", RecordPath.compile("substring(/name, 1000, 1005)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("", RecordPath.compile("substring(/name, 4, 3)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substring(/name, 0, 10000)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("", RecordPath.compile("substring(/name, -50, -1)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testSubstringBeforeFunction() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("John", RecordPath.compile("substringBefore(/name, ' ')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringBefore(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringBefore(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("John D", RecordPath.compile("substringBeforeLast(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringBeforeLast(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringBeforeLast(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testSubstringAfterFunction() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("hn Doe", RecordPath.compile("substringAfter(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringAfter(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringAfter(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("e", RecordPath.compile("substringAfterLast(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringAfterLast(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("substringAfterLast(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testContains() { + final Record record = createSimpleRecord(); + assertEquals("John Doe", RecordPath.compile("/name[contains(., 'o')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[contains(., 'x')]").evaluate(record).getSelectedFields().count()); + + record.setValue("name", "John Doe 48"); + assertEquals("John Doe 48", RecordPath.compile("/name[contains(., /id)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testStartsWith() { + final Record record = createSimpleRecord(); + assertEquals("John Doe", RecordPath.compile("/name[startsWith(., 'J')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[startsWith(., 'x')]").evaluate(record).getSelectedFields().count()); + assertEquals("John Doe", RecordPath.compile("/name[startsWith(., '')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testEndsWith() { + final Record record = createSimpleRecord(); + assertEquals("John Doe", RecordPath.compile("/name[endsWith(., 'e')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[endsWith(., 'x')]").evaluate(record).getSelectedFields().count()); + assertEquals("John Doe", RecordPath.compile("/name[endsWith(., '')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testIsEmpty() { + final Record record = createSimpleRecord(); + assertEquals("John Doe", RecordPath.compile("/name[isEmpty(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("/name[isEmpty(/missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[isEmpty(../id)]").evaluate(record).getSelectedFields().count()); + + record.setValue("missing", " "); + assertEquals(0L, RecordPath.compile("/name[isEmpty(/missing)]").evaluate(record).getSelectedFields().count()); + } + + + @Test + public void testIsBlank() { + final Record record = createSimpleRecord(); + assertEquals("John Doe", RecordPath.compile("/name[isBlank(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + record.setValue("missing", " "); + assertEquals("John Doe", RecordPath.compile("/name[isBlank(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("/name[isBlank(/missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[isBlank(../id)]").evaluate(record).getSelectedFields().count()); + } + + @Test + public void testContainsRegex() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("John Doe", RecordPath.compile("/name[containsRegex(., 'o')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("/name[containsRegex(., '[xo]')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[containsRegex(., 'x')]").evaluate(record).getSelectedFields().count()); + } + + @Test + public void testNot() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("John Doe", RecordPath.compile("/name[not(contains(., 'x'))]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[not(. = 'John Doe')]").evaluate(record).getSelectedFields().count()); + assertEquals("John Doe", RecordPath.compile("/name[not(. = 'Jane Doe')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testChainingFunctions() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("John Doe", RecordPath.compile("/name[contains(substringAfter(., 'o'), 'h')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + + + @Test + public void testMatchesRegex() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals(0L, RecordPath.compile("/name[matchesRegex(., 'John D')]").evaluate(record).getSelectedFields().count()); + assertEquals("John Doe", RecordPath.compile("/name[matchesRegex(., '[John Doe]{8}')]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testReplace() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("John Doe", RecordPath.compile("/name[replace(../id, 48, 18) = 18]").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(0L, RecordPath.compile("/name[replace(../id, 48, 18) = 48]").evaluate(record).getSelectedFields().count()); + + assertEquals("Jane Doe", RecordPath.compile("replace(/name, 'ohn', 'ane')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("replace(/name, 'ohnny', 'ane')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("John 48", RecordPath.compile("replace(/name, 'Doe', /id)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("23", RecordPath.compile("replace(/id, 48, 23)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testReplaceRegex() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals("ohn oe", RecordPath.compile("replaceRegex(/name, '[JD]', '')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals("John Doe", RecordPath.compile("replaceRegex(/name, 'ohnny', 'ane')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("11", RecordPath.compile("replaceRegex(/id, '[0-9]', 1)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("Jxohn Dxoe", RecordPath.compile("replaceRegex(/name, '([JD])', '$1x')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("Jxohn Dxoe", RecordPath.compile("replaceRegex(/name, '(?<hello>[JD])', '${hello}x')").evaluate(record).getSelectedFields().findFirst().get().getValue()); + + assertEquals("48ohn 48oe", RecordPath.compile("replaceRegex(/name, '(?<hello>[JD])', /id)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testReplaceNull() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + fields.add(new RecordField("missing", RecordFieldType.LONG.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + + assertEquals(48, RecordPath.compile("replaceNull(/missing, /id)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(14, RecordPath.compile("replaceNull(/missing, 14)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + assertEquals(48, RecordPath.compile("replaceNull(/id, 14)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + + @Test + public void testConcat() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("fullName", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("lastName", RecordFieldType.STRING.getDataType())); + fields.add(new RecordField("firstName", RecordFieldType.LONG.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("lastName", "Doe"); + values.put("firstName", "John"); + final Record record = new MapRecord(schema, values); + + assertEquals("John Doe: 48", RecordPath.compile("concat(/firstName, ' ', /lastName, ': ', 48)").evaluate(record).getSelectedFields().findFirst().get().getValue()); + } + private List<RecordField> getDefaultFields() { final List<RecordField> fields = new ArrayList<>(); fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); @@ -738,4 +1023,19 @@ public class TestRecordPath { return accountSchema; } + private Record createSimpleRecord() { + final List<RecordField> fields = new ArrayList<>(); + fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); + fields.add(new RecordField("name", RecordFieldType.STRING.getDataType())); + fields.add(new RecordField("missing", RecordFieldType.STRING.getDataType())); + + final RecordSchema schema = new SimpleRecordSchema(fields); + + final Map<String, Object> values = new HashMap<>(); + values.put("id", 48); + values.put("name", "John Doe"); + final Record record = new MapRecord(schema, values); + return record; + } + } http://git-wip-us.apache.org/repos/asf/nifi/blob/32314d70/nifi-docs/src/main/asciidoc/record-path-guide.adoc ---------------------------------------------------------------------- diff --git a/nifi-docs/src/main/asciidoc/record-path-guide.adoc b/nifi-docs/src/main/asciidoc/record-path-guide.adoc index d38a5d3..c5ba3ff 100644 --- a/nifi-docs/src/main/asciidoc/record-path-guide.adoc +++ b/nifi-docs/src/main/asciidoc/record-path-guide.adoc @@ -157,6 +157,15 @@ when we reference an Array field and want to only reference some of the elements specific entries in the Map; or when we want to reference a Record only if it adheres to some criteria. We can accomplish this by providing our criteria to the RecordPath within square brackets (using the `[` and `]` characters). We will go over each of these cases below. +[[function_usage]] +== Function Usage + +In addition to retrieving a field from a Record, as outlined above in the <<filters>> section, we sometimes need to refine which fields we want to select. Or we +may want to return a modified version of a field. To do this, we rely on functions. The syntax for a function is <function name> <open parenthesis> <args> <close parenthesis>, +where <args> represents one or more arguments separated by commas. An argument may be a string literal (such as `'hello'`) or a number literal (such as `48`), or could be +a relative or absolute RecordPath (such as `./name` or `/id`). Additionally, we can use functions within a filter. For example, we could use a RecordPath such as +`/person[ isEmpty('name') ]/id` to retrieve the `id` field of any person whose name is empty. A listing of functions that are available and their corresponding documentation +can be found below in the <<functions>> section. [[arrays]] === Arrays @@ -291,3 +300,246 @@ value of the `preferredState` field. Additionally, we can write a RecordPath that references the "city" field of any record whose state is "NJ" by using the parent operator (`..`): `/*/city[../state = 'NJ']`. + +[[functions]] +== Functions + +In the <<function_usage>> section above, we describe how and why to use a function in RecordPath. Here, we will describe the different functions that are available, +what they do, and how they work. Functions can be divided into two groups: <<standalone_functions>>, which can be the 'root' of a RecordPath, such as `substringAfter( /name, ' ' )` +and <<filter_functions>>, which are to be used as a filter, such as `/name[ contains('John') ]`. A Standalone Function can also be used within a filter but does not return a `boolean` +(`true` or `false` value) and therefore cannot itself be an entire filter. For example, we can use a path such as `/name[ substringAfter(., ' ') = 'Doe']` but we cannot simply use +`/name[ substringAfter(., ' ') ]` because doing so doesn't really make sense, as filters must be boolean values. + +Unless otherwise noted, all of the examples below are written to operate on the following Record: + +---- +{ + "name": "John Doe", + "workAddress": { + "number": "123", + "street": "5th Avenue", + "city": "New York", + "state": "NY", + "zip": "10020" + }, + "homeAddress": { + "number": "456", + "street": "Grand St", + "city": "Jersey City", + "state": "NJ", + "zip": "07304" + }, + "details": { + "position": "Dataflow Engineer", + "preferredState": "NY", + "employer": "", + "vehicle": null, + "phrase": " " + } +} +---- + + +[[standalone_functions]] +== Standalone Functions + +=== substring + +The substring function returns a portion of a String value. The function requires 3 arguments: The value to take a portion of, the 0-based start index (inclusive), +and the 0-based end index (exclusive). The start index and end index can be `0` to indicate the first character of a String, a positive integer to indicate the nth index +into the string, or a negative integer. If the value is a negative integer, say `-n`, then this represents the `n`th character for the end. A value of `-1` indicates the last +character in the String. So, for example, `substring( 'hello world', 0, -1 )` means to take the string `hello`, and return characters 0 through the last character, so the return +value will be `hello world`. + +|========================================================== +| RecordPath | Return value +| `substring( /name, 0, -1 )` | John Doe +| `substring( /name, 0, -5 )` | John +| `substring( /name, 1000, 1005 )` | <empty string> +| `substring( /name, 0, 1005)` | John Doe +| `substring( /name, -50, -1)` | <empty string> +|========================================================== + + + +=== substringAfter + +Returns the portion of a String value that occurs after the first occurrence of some other value. + +|========================================================== +| RecordPath | Return value +| `substringAfter( /name, ' ' )` | Doe +| `substringAfter( /name, 'o' )` | hn Doe +| `substringAfter( /name, '' )` | John Doe +| `substringAfter( /name, 'xyz' )` | John Doe +|========================================================== + + +=== substringAfterLast + +Returns the portion of a String value that occurs after the last occurrence of some other value. + +|========================================================== +| RecordPath | Return value +| `substringAfterLast( /name, ' ' )` | Doe +| `substringAfterLast( /name, 'o' )` | e +| `substringAfterLast( /name, '' )` | John Doe +| `substringAfterLast( /name, 'xyz' )` | John Doe +|========================================================== + + + +=== substringBefore + +Returns the portion of a String value that occurs before the first occurrence of some other value. + +|========================================================== +| RecordPath | Return value +| `substringBefore( /name, ' ' )` | John +| `substringBefore( /name, 'o' )` | J +| `substringBefore( /name, '' )` | John Doe +| `substringBefore( /name, 'xyz' )` | John Doe +|========================================================== + + + +=== substringBeforeLast + +Returns the portion of a String value that occurs before the last occurrence of some other value. + +|========================================================== +| RecordPath | Return value +| `substringBeforeLast( /name, ' ' )` | John +| `substringBeforeLast( /name, 'o' )` | John D +| `substringBeforeLast( /name, '' )` | John Doe +| `substringBeforeLast( /name, 'xyz' )` | John Doe +|========================================================== + + + +=== replace + +Replaces all occurrences of a String with another String. + +|========================================================== +| RecordPath | Return value +| `replace( /name, 'o', 'x' )` | Jxhn Dxe +| `replace( /name, 'o', 'xyz' )` | Jxyzhn Dxyze +| `replace( /name, 'xyz', 'zyx' )` | John Doe +| `replace( /name, 'Doe', /workAddress/city )` | John New York +|========================================================== + + + +=== replaceRegex + +Evaluates a Regular Expression against the contents of a String value and replaces any match with another value. +This function requires 3 arguments: the String to run the regular expression against, the regular expression to run, +and the replacement value. The replacement value may optionally use back-references, such as `$1` and `${named_group}` + +|================================================================== +| RecordPath | Return value +| `replaceRegex( /name, 'o', 'x' )` | Jxhn Dxe +| `replaceRegex( /name, 'o', 'xyz' )` | Jxyzhn Dxyze +| `replaceRegex( /name, 'xyz', 'zyx' )` | John Doe +| `replaceRegex( /name, '\s+.*', /workAddress/city )` | John New York +| `replaceRegex(/name, '([JD])', '$1x')` | Jxohn Dxoe +| `replaceRegex(/name, '(?<hello>[JD])', '${hello}x')` | Jxohn Dxoe +|================================================================== + + + +[[filter_functions]] +== Filter Functions + +=== contains + +Returns `true` if a String value contains the provided substring, `false` otherwise + +|============================================================================== +| RecordPath | Return value +| `/name[contains(., 'o')]` | John Doe +| `/name[contains(., 'x')]` | <returns no results> +| `/name[contains( ../workAddress/state, /details/preferredState )]` | John Doe +|============================================================================== + + + +=== matchesRegex + +Evaluates a Regular Expression against the contents of a String value and returns `true` if the Regular Expression +exactly matches the String value, `false` otherwise. +This function requires 2 arguments: the String to run the regular expression against, and the regular expression to run. + +|============================================================================== +| RecordPath | Return value +| `/name[matchesRegex(., 'John Doe')]` | John Doe +| `/name[matchesRegex(., 'John')]` | <returns no results> +| `/name[matchesRegex(., '.* Doe' )]` | John Doe +|============================================================================== + + + +=== startsWith + +Returns `true` if a String value starts with the provided substring, `false` otherwise + +|============================================================================== +| RecordPath | Return value +| `/name[startsWith(., 'J')]` | John Doe +| `/name[startsWith(., 'x')]` | <returns no results> +| `/name[startsWith(., 'xyz')]` | <returns no results> +| `/name[startsWith(., '')]` | John Doe +|============================================================================== + + +=== endsWith + +Returns `true` if a String value ends with the provided substring, `false` otherwise + +|============================================================================== +| RecordPath | Return value +| `/name[endsWith(., 'e')]` | John Doe +| `/name[endsWith(., 'x')]` | <returns no results> +| `/name[endsWith(., 'xyz')]` | <returns no results> +| `/name[endsWith(., '')]` | John Doe +|============================================================================== + + +=== not + +Inverts the value of the function or expression that is passed into the `not` function. + +|============================================================================== +| RecordPath | Return value +| `/name[not(endsWith(., 'x'))]` | John Doe +| `/name[not(contains(., 'x'))]` | John Doe +| `/name[not(endsWith(., 'e'))]` | <returns no results> +|============================================================================== + + +=== isEmpty + +Returns `true` if the provided value is either null or is an empty string. + +|============================================================================== +| RecordPath | Return value +| `/name[isEmpty(/details/employer)]` | John Doe +| `/name[isEmpty(/details/vehicle)]` | John Doe +| `/name[isEmpty(/details/phase)]` | <returns no results> +| `/name[isEmpty(.)]` | <returns no results> +|============================================================================== + + +=== isBlank + +Returns `true` if the provided value is either null or is an empty string or a string that consists +only of white space (spaces, tabs, carriage returns, and new-line characters). + +|============================================================================== +| RecordPath | Return value +| `/name[isBlank(/details/employer)]` | John Doe +| `/name[isBlank(/details/vehicle)]` | John Doe +| `/name[isBlank(/details/phase)]` | John Doe +| `/name[isBlank(.)]` | <returns no results> +|============================================================================== http://git-wip-us.apache.org/repos/asf/nifi/blob/32314d70/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/UpdateRecord.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/UpdateRecord.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/UpdateRecord.java index 6acc789..abe29a2 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/UpdateRecord.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/UpdateRecord.java @@ -188,7 +188,7 @@ public class UpdateRecord extends AbstractRecordProcessor { private void processRelativePath(final RecordPath replacementRecordPath, final Stream<FieldValue> destinationFields, final Record record, final String replacementValue) { destinationFields.forEach(fieldVal -> { - final RecordPathResult replacementResult = replacementRecordPath.evaluate(fieldVal); + final RecordPathResult replacementResult = replacementRecordPath.evaluate(record, fieldVal); final Object replacementObject = getReplacementObject(replacementResult, replacementValue); fieldVal.updateValue(replacementObject); });
