Executing eval on a delimited string - InfoPath Dev

InfoPath Dev

Use our Google Custom Search for best site search results.

Executing eval on a delimited string

Last post 09-08-2013 11:42 PM by Tim Holzmann. 2 replies.
Page 1 of 1 (3 items)
Sort Posts: Previous Next
  • 08-24-2013 06:16 PM

    Executing eval on a delimited string

    Hello, Ok, I just found that my line breaks are not showing up, so this will be hard to read -- my apologies. I'm trying to pass info out of form's repeating table. Unfortunately, I cannot use QRules because of network security policies. My solution is to build a delimited string that essentially serves the purpose of a hash file. Columns are separated by a comma and rows are separated by a semicolon. I have found that I need a separate row for every item in a secondary data source (see side note at the end for the reason). I use a double eval to iterate through the secondary data source, building a zeroed list like this: my:fullList (field) -- item 1: feature1: 0, feature2: 0; item 2: feature1: 0, feature2: 0; In the form, users can use a dropdown to select items from the same secondary data source and add feature values. This information is stored in a repeating group like this: my:RepeatingGroup /itemID /values (group) /feature1Val /feature2Val My problem is now to make a rule for the submit button that evals each /my:RepeatingGroup/my:itemID and adds /featureXVal to the matching row/column value in /my:fullList. I think I need something like this: eval(/itemID, 'concat(substring-before(my:fullList, concat("Item ", .)), "Item ", ., ": feature1: ", substring-before(substring-after(substring-after(my:fullList, concat("Item ", ., ":")), "feature1: ", ",") + ../feature1Val, ", feature2: ", substring-before(substring-after(substring-after(my:fullList, concat("Item ", ., ":")), "feature2: ", ",") + ../feature2Val, ";", substring-after(substring-after(my:fullList, concat(Item ", .)), ";")') What this should do is for each /itemID build the following string and then pass that on to the next /itemID: - [everything in my:fullList that comes before the current item] - "Item " - [current itemID] - ": feature1: " - [old feature 1 value] + /feature1Val - ", feature2: " - [old feature2 value] + /feature2Val - [everything in my:fullList that comes after the ";" that ends the current item] However, when I try to put this in an "eval" function, each iteration works on /my:fullList anew, rather than the function output of the last iteration. Rather than sequential edits on the same string, the function is returning parallel edits and outputs the first one. (Side note: I looked a just doing a double eval on /my:RepeatingGroup, but not all of these forms will include all the items. I parse and sum these strings in a separate form (using the same chained substring technique), and if a given "Item X" is not in the string, the substring function returns "", which is NaN and breaks the sum function. An alternative solution to my problem would be to find a function (similar to the chained substring technique) that parses the following string: "item 1: feature1: 1, feature2: 2; item 3: feature1: 3, feature2: 4". And returns "1" for item1, feature 1, and returns "0" for item2, feature1 (which is not included here, since the string only includes items 1 and 3). I tried using nz(), but that didn't work, though I'm not sure why.)
  • 09-08-2013 02:59 PM In reply to

    Re: Executing eval on a delimited string

    Why not just add a column to the repeating group and use a rule-action to set that column. That will fire a rule on each row in the repeating group and you can add another rule to the repeating with a condition to prevent double firing and an action to tack on the featureXVal based on the current row (using the current() xpath function)?  I covered this in one of my examples in my August 29th webinar: http://youtu.be/vQTkRBTSIos?t=28m10s


    Patrick Halstead
    Project Manager at Qdabra
  • 09-08-2013 11:42 PM In reply to

    Re: Executing eval on a delimited string


    Thanks for the response.  I ended up solving the problem using the second option.  So, the users enter data into repeating tables on forms for a sharepoint library.  This data is concatenated (using a double-eval) into a single string and promoted to a column in the sharepont library like this:

    Form 1 dataField: "item 1: feature1: 1, feature2: 2; item 3: feature1: 3, feature2: 4,"

    Form 2 dataField: "item 1: feature1: 5, feature2: 0; item 2: feature1: 6, feature2: 1; item 3: feature1: 9, feature2: 13,"

    (Note: the first entry does not have any data for "item 2" but the second does.)

    Then I read that as a secondary data source in another form, and I want to sum all the related fields in a repeating table that has a new row for each item. Users pick items (itemID), and the form takes all the data from the secondary data source, goes through each feature, and computes the sum.  We can this in three steps:

    1) We need to store the current row itemID as a temporary variable.  I used the secondary data source as a convenient holding spot (convenient as long as I don't want to requery, which I don't).  On changing the itemID in the row ofthe destination table, I use a rule (runs when this field changes) to set the field

    [secondaryTable path]/q:SharePointListItem_RW/q:ID = concat("item ", .)

    2) I need to read all the rows of the secondary data source, lookup my current itemID (now stored in [secondaryTable path]/q:SharePointListItem_RW/q:ID) and sum the values associated with each feature.  This requires a separate rule for each feature.  Here's a piece of code for feature1:

    sum(eval( [secondaryTable path] /d:SharePointListItem_RW/d:dataField, 'concat(substring-before(substring-after(substring-after(., concat("item ",[secondaryTable path]/q:SharePointListItem_RW/q:ID)), "feature1: "), ",")'))

    For item 1, feature 2, the eval reads through both rows of of data and finds "2" + "0" = 2.  Note: we are using a special feature of InfoPath (and possibly XPath, I'm not sure) that it allows doing math on strings, provided that the strings are composed strictly of numerals.  The problem is, that in the example above, the above function will return a null string ("") when looking for "item 2" in the first row of data above, and InfoPath evaluates "" as NaN rather than 0 for math. So the for item 2, feature1 in the sample data the function returns "" + "6" = NaN.

    The solution is a conditional substring technique that allows us to use if/then logic to return "0" for empty strings (http://blogs.msdn.com/b/infopath/archive/2006/11/27/conditional-default-values.aspx).  The new code reads:

    sum(eval( my:fullList, 'concat(substring-before(substring-after(substring-after(., concat("item ",[secondaryTable path]/q:SharePointListItem_RW/q:ID)), "feature1: "), ","), substring("0", 1, not(contains(., concat("item ",[secondaryTable path]/q:SharePointListItem_RW/q:ID))))'))

    The second part that concatenates a "0" to the returned string if the item is not found.  ie. for the example data above, Form 1 dataField (inside the revised eval function) would evaluate to concat("", "0").  So in the example for item 2, feature 1, the function now returns "0" + "6" = 12.

     3) Finally we clean up our mess by resetting our temporary holder with one more rule:

    [secondaryTable path]/q:SharePointListItem_RW/q:ID = ""


Page 1 of 1 (3 items)
Copyright © 2003-2019 Qdabra Software. All rights reserved.
View our Terms of Use.