Good morning,
I'm trying to learn BizTalk and it's doing something I don't understand.
I'm outputting XML for employee addresses. A looping functoid creates two "Communication" elements. I expected to see the "CountrySubDivisionCode" as child elements in BOTH of them but they appear only once:
<ns0:Communication sequence="1">
<ns0:ChannelCode>Telephone</ns0:ChannelCode>
<ns0:UseCode>Personal</ns0:UseCode>
<ns0:DialNumber>1234567890</ns0:DialNumber>
<ns0:Address>
<ns0:AddressLine sequence="1">1234 My St</ns0:AddressLine>
<ns0:CityName>Some City</ns0:CityName>
<ns0:CountrySubDivisionCode name="County">Jackson</ns0:CountrySubDivisionCode>
<ns0:CountrySubDivisionCode name="State">MO</ns0:CountrySubDivisionCode>
<ns0:CountryCode>US</ns0:CountryCode>
<ns0:PostalCode>14099</ns0:PostalCode>
</ns0:Address>
</ns0:Communication>
<ns0:Communication sequence="2">
<ns0:ChannelCode>Telephone</ns0:ChannelCode>
<ns0:UseCode>Business</ns0:UseCode>
<ns0:DialNumber>0987654321</ns0:DialNumber>
<ns0:Address>
<ns0:AddressLine sequence="1">1234 My St</ns0:AddressLine>
<ns0:CityName>Some City</ns0:CityName>
<ns0:CountryCode>US</ns0:CountryCode>
<ns0:PostalCode>14099</ns0:PostalCode>
</ns0:Address>
</ns0:Communication>
The input is a flat schema.
There's one looping functiod for the Communication element with telephone numbers. It's output is the Communication element in the output schema.
There's another looping functoid with state and county inputs, It's output is
the CountrySubDivisionCode element in the output schema.
How is the mapping deciding what is output and what is not? Is it not outputting
the second set because they would be duplicates? All the tutorials I've found
seem to be copy and paste versions of the same source material and it's pretty light.
Thanks
Validate the map (right click in the Solution Explorer) and click on the XSL link in the visual studio output window. This the the best way to figure out what the mapper is doing as you'll see the XSLT that is generated.
I was able to fix this by experimentation. I believe how the looping functoid works is this:
it creates a list of input values from each of the inputs
It iterates through the list creating one output for each input. When it does this it REMOVES (NOT nulls or empties) the other inputs.
Once the list is exhausted there are NO outputs (the list is empty).
I had "nested" looping functoids. The outer functoid had three inputs and the inner functoid had two inputs. On the first outer functoid output it used both of the two inputs from the inner functoid (which were suppressed because of the position and lost). On all subsequent outer functoid outputs the inner functoid had no further values to use so it output nothing.
For my solution I had to rearrange the inputs to the outer functoid so the address portion came first. The inner functoid output the two country divisions correctly. For the subsequent telephone rows there were no remaining outputs and none were desired.
Michael and Mousio thanks for the help!
Related
I have tens of thousands of rows of unstructured data in csv format. I need to extract certain product attributes from a long string of text. Given a set of acceptable attributes, if there is a match, I need it to fill in the cell with the match.
Example data:
"[ROOT];Earrings;Brands;Brands>JeweleryExchange;Earrings>Gender;Earrings>Gemstone;Earrings>Metal;Earrings>Occasion;Earrings>Style;Earrings>Gender>Women's;Earrings>Gemstone>Zircon;Earrings>Metal>White Gold;Earrings>Occasion>Just to say: I Love You;Earrings>Style>Drop/Dangle;Earrings>Style>Fashion;Not Visible;Gifts;Gifts>Price>$500 - $1000;Gifts>Shop>Earrings;Gifts>Occasion;Gifts>Occasion>Christmas;Gifts>Occasion>Just to say: I Love You;Gifts>For>Her"
Look up table of values:
Zircon, Diamond, Pearl, Ruby
Output:
Zircon
I tried using the VLOOKUP() function, but it needs to match an entire cell and works better for translating acronyms. Haven't really found a built in function that accomplishes what I need. The data is totally unstructured, and changes from row to row with no consistency even within variations of the same product. Does anyone have an idea how to do this?? Or how to write an OpenOffice Calc function to accomplish this? Also open to other better methods of doing this if anyone has any experience or ideas in how to approach this...
ok so I figured out how to do this on my own... I created many different columns, each with a keyword I was looking to extract as a header.
Spreadsheet solution for structured data extraction
Then I used this formula to extract the keywords into the correct row beneath the column header. =IF(ISERROR(SEARCH(CF$1,$D769)),"",CF$1) The Search function returns a number value for the position of a search string otherwise it produces an error. I use the iserror function to determine if there is an error condition, and the if statement in such a way that if there is an error, it leaves the cell blank, else it takes the value of the header. Had over 100 columns of specific information to extract, into one final column where I join all the previous cells in the row together for the final list. Worked like a charm. Recommend this approach to anyone who has to do a similar task.
I have some data which looks something like this:
<wrapper>
<inner a="1"/>
<inner a="2" b="3"/>
</wrapper>
The attribute b may or may not be present on each inner element. My aim is to find all documents containing at least one inner element that doesn't have attribute b.*
This similar question proposes the answer:
cts:not-query(cts:element-attribute-value-query(xs:QName('inner'), xs:QName('b'), '*', ("wildcarded"))))
but that doesn't work, because some inner elements on the same document may have attribute b, and not-queries work on the entire fragment, so a mixed case like the example above would not be returned. Wrapping it in an element-query doesn't help, and cts:and-not-query seems to behave the same way.
I have also tried attacking the problem using co-occurrence/values functions to read the values of relevant attributes a, but that also seems to be impossible. It might have been possible with proximity settings on co-occurrences calls except there is no element text, so the attribute are indexed with the same word positions.
Are there any alternatives to the blunt xpath?
//inner[#a and not(#b)]
You can always make the xpath more complicated if simplicity isnt your goal.
How about this one: (it more accurately answers the exact question of 'return all documents that contain 'innner' elements that do not have an atribute #b'
doc()[exists(//inner[not(#b)])]
I do not know how well this is optimized -- some xpath expressions optimize down to the equivalent cts: query and some do not.
There is another 'trick' involving combining cts expressions represented as maps. Take the results of 2 searches, use the options that return the results as a map, then you can use the operations on this page https://developer.marklogic.com/blog/im-a-map to do extremely efficient set operations (union, intersection, difference etc). When properly constructed, this technique can be as fast as 'native' cts searches --- the cts searches use the same general technique internally for resolving results.
Make the XPath a path range index. //inner[#a and not(#b)], or if there's no element text, //inner[#a and not(#b)]/#a, then do
cts:path-range-query('//inner[#a and not(#b)]/#a','>','')
This happens to also allow us to efficiently answer the question of which #a values have a missing #b, using cts:values.
cts:not-in-query has the necessary behaviour to make this work where cts:and-not-query doesn’t. E.g.
cts:not-in-query(
cts:element-query(xs:QName('inner'), cts:true-query()),
cts:element-attribute-query(xs:QName('inner'), xs:QName('b'),'*','wildcarded')
)
Finds all ‘inner’ elements at positions that do not match the positions of ‘inner’ elements with attribute b.
Element position index must be enabled. Wildcard index must be enabled.
http://docs.marklogic.com/cts:not-in-query
I am fairly new to using PeopleSoft BI Publisher plugin for MS Word and integrating it with PS Query Manager. My question is whether in the RTF file you can put logic to suppress or filter out data?
I have a for-each grouping that prints a line (row). I would like to add logic to NOT print the line if the Witholding amount field (M.WTHD_AMT) is equal to 0 (zero). My question is what would the syntax look like, and where should I place it (on the For Each grouping below, the Field level, or somewhere else?) I know I can alter the PS Query (data source) to do the filtering but I would like to leave that as-is and handle this in the template.
I see that there is another conditional IF statement ("rmt_") so I'm not sure if I can add this additional logic to that element or if I need a separate one. I appreciate any feedback!
EDIT:
I've added a new "Conditional Region" as suggested, and it works with just the WTHD_AMT criteria !0 to zero, however I tried added additional criteria where L.PYMNT_TYPE = 'R' and when I run the process it doesn't display data on the PDF output. Is there something wrong with the syntax? Do I need to have a separate Conditional Region for this 2nd criteria? I've seen another BI report where they have 2 or 3 criteria as part of one element.
<?if:number(M.WTHD_AMT)!=0.00?> and <?if:L.PYMNT_TYPE='R'?>
Option 1
You can nest <?if?> statements. Just add another <?end if?> at the end. Make sure there are no spaces between the all of the IF or END IF objects at the beginning or end of the content/row, else the row may still be displayed.
Option 2
You can add conditions in the repeating section. Below will repeat the region for every record where M.WTHD_AMT is not 0.00
<?for-each:record_path/record[M.WTHD_AMT!='0.00']?>
'Conditional Region' is the button you are looking for.
When using this button, make sure to double check where the if/endif or C/EC elements are added. It tends to ignore the selected element and join the elements to the start and end of the line. You will then need to cut and paste it into the right spot. For you this will probably be right after the F element and before the E element.
Alright, I've been given a program that requires me to take a .txt file of varying symbols in rows and columns that would look like this.
..........00
...0....0000
...000000000
0000.....000
............
..#########.
..#...#####.
......#####.
...00000....
and using command arguments to specify row and column, requires me to select a symbol and replace that symbol with an asterisk. The problem i have with this is that it then requires me to recur up, down, left, and right any of the same symbol and change those into an asterisk.
As i understand it, if i were to enter "1 2" into my argument list it would change the above text into.
**********00
***0....0000
***000000000
0000.....000
............
..#########.
..#...#####.
......#####.
...00000....
While selecting the specified character itself isn't a problem, how do i have any similar, adjacent symbols change and then the ones next to those. I have looked around but can't find any information and as my teacher has had a different subs for the last 3 weeks, i havent had a chance to clarify my questions with them. I've been told that recursion can be used, but my actual experience using recursion is limited. Any suggestions or links i can follow to get a better idea on what to do? Would it make sense to add a recursive method that takes the coordinates given adds and subtracts from the row and column respectively to check if the symbol is the same and repeats?
Load in char by char, row by row, into a 2D array of characters. That'll make it a lot easier to move up and down and left and right, all you need to do is move one of the array indexes.
You can also take advantage of recursion. Make a function that changes all adjacent matching characters, and then call that same function on all adjacent matching characters.
I want to know if there is a way to check for the last element in a fusion for_each loop (in order to apply special code for this case)
Edit : Maybe a better question should be :
I have played with fusion::for_each, now I want to apply code on each element of a fusion sequence with special code (special code does not mean "extra code" but different code) for the last element. May be I should use iterators (an example please)?
Some ideas:
1) use boost::fusion::fold, count your way though, and on the last one, perform your edit
2) if all types in the tuple are heterogenous, match on type to determine last one
3) include some sort of marker for the last one on which you can match
4) use the 'prior(end(v))' operators to manipulate the last element when for_each processing is complete