Concatenating values from the repeating nodes under repeating nodes in BizTalk Maps - concatenation

I have something like this in an input XML
<Root>
<OrderText>
<item>item1</item>
<item>item2</item>
</OrderText>
<OrderText>
<item>item3</item>
<item>item4</item>
<item>item5</item>
</OrderText>
</Root>
From this input, the desired output is
<Root>
<OrderItems>
<Items>item1#item2</Items>
</OrderItems>
<OrderItems>
<Items>item3#item4#item5</Items>
</OrderItems>
</Root>
I am trying to find a solution here and followed a question asked by myself long back (link How to Concatenate multiple repetitive nodes into a single node - BizTalk)
but with that approach I'm getting result like below
<Root>
<OrderItems>
<Items>item1#item2#item3#item4#item5</Items>
</OrderItems>
<OrderItems>
<Items>item1#item2#item3#item4#item5</Items>
</OrderItems>
</Root>
which is totally wrong. can somebody help me please.

Have a look at the documentation Cumulative Concatenate Functoid
That gives you the first clue
Parameter 2: An optional numeric value that indicates the scope to which the accumulation should be performed. The default value is zero (0), indicating that the accumulation scope is the entire input instance message.
Try adding the second parameter and setting it to 1. This will result in the below output, which is closer to what you want.
<Root>
<OrderItems>
<Items>item1#item2#</Items>
<Items>item3#item4#item5#</Items>
</OrderItems>
</Root>
The second clue can be found by going to the Error List, showing Messages and clicking on the "Double-click here to show/hide compiler links". That will cause orange lines to appear on the map surface showing how the map thinks it should loop. See screenshot above that also shows that. Note how it is only looping on the root?
So the second fix is to draw a line from OrderText to OrderItems, and when prompted select Direct Link, which is telling it you want it to loop there as well.
This will give you on output close to your desired output of
<Root>
<OrderItems>
<Items>item1#item2#</Items>
</OrderItems>
<OrderItems>
<Items>item3#item4#item5#</Items>
</OrderItems>
</Root>
Removing the extra # at the end could be done either with a number of fuctoids such as string Size, String Left and a Subtraction functoid, or using a Scripting Fuctoid.

Related

Passing a List to an sql-component query

I'm having trouble to pass a list of string I'm getting back from my bean to my sql-component query to make a call to the database.
<bean ref="fo" method="transformTo(${body})" />
So in this upper line of code I'm taking data from the body that is an xml and transform it to json.
<bean ref="fot" method="getOTs(${body})" />
Then I'm extracting the part I want from the json and return a list of string (method signature) :
public List<String> getOTs(String jsonOTs)
Now the part that isn't working (I'm getting that one parameter is expected but there are a couple each time)
<to uri="sql:insert into dbo.table_example (OT) VALUES :#body;"/>
My goal is quite simple, retrieving a list of string from my bean (working) and making and an insert into query. I have only one parameter but multiple values. Example:
INSERT INTO table_name (column_list)
VALUES
(value_list_1),
(value_list_2),
...
(value_list_n);
Example taken from here
Bulk insert
For a bulk insert, you need to set the query parameter batch to true, this way, Camel will understand that you want to insert several rows in one batch.
Here is the corresponding to endpoint in your case:
<to uri="sql:insert into dbo.table_example (OT) VALUES (#)?batch=true"/>
Miscellaneous remarks
Actually, for all the use cases that you listed above, you have no need to explicitly refer to the body.
Indeed, in the case of a bean, you could only specify the method to invoke, Camel is able to inject the body as a parameter of your method and automatically converts it into the expected type which is String in your case.
Refers to https://camel.apache.org/manual/bean-binding.html#_parameter_binding for more details.
Regarding the SQL producer, assuming that you did not change the default configuration, the proper way is to rather use the placeholder that is # by default, Camel will automatically use the content of the body as parameters of the underlying PreparedStatement.
So you should retry with:
<to uri="sql:insert into dbo.table_example (OT) VALUES (#)"/>
If you really want to explicitly refer to the body in your query, you can rather use :#${body} as next:
<to uri="sql:insert into dbo.table_example (OT) VALUES (:#${body})"/>
Misuse of named parameter
If you only use #body as you did, Camel interprets it as a named parameter so it will try to get the value from the body if it is a map by getting the value of the key body otherwise it will try to get the value of the header body but in your case, there are no such values, therefore, you end up with an error of type
Cannot find key [body] in message body or headers to use when setting named
parameter in query [insert into developers (name) values :?body;] on the exchange

SQL Server 2008 Xml Issue With Xml Escape Characters

Our current Point of Sale system executes too many queries in nested transactions that leave duplicated or partial data in place. I changed the entire thing to a single stored procedure where all sale item data is passed in as Xml, iterated through in a temp table, and saved to the database, then committed. However, SQL rejects special characters in the xml.
For example:
<?xml version="1.0" encoding="utf-16"?>
<list>
<item>
<objectid>bd99fcb6-3031-48b7-9a71-5f8cefe0a614</objectid>
<amount>50.00</amount>
<fee>1.50</fee>
<waivedfee>0.00</waivedfee>
<tax>0.00</tax>
<name>TEST & TEST PERSON</name>
<payeeid>197</payeeid>
<accountnumber>5398520352</accountnumber>
<checknumber />
<comedreceiptnumber />
<isexpedited>0</isexpedited>
<echeckrefnumber />
</item>
</list>
Fails. It tells me that there is an illegal character where & is located. I don't know why. It's escaped properly with &. I can't find any solutions online, anywhere. Everywhere people tell me to replace & with & - which is what I am doing!
Use XML PATH(''), it will encode the special characters for you.
SELECT 'TEST & TEST PERSON' FOR XML PATH('')
I figured it out. UTF-16 is correct. That Xml is fine. There was a final piece of xml, the ledgers, that were just plain strings with no encoding and no escaping special characters. Once I corrected that it all worked.
Thanks for the help!

How to avoid in SQL to store an XML <option></option> like <option />?

When I try to store a XML in SQL than have an empty Element, SQL just change it and store it with only one tag for the element.
For Example the XML to store is:
<ROOT>
<FIRSTNAME>ROGER</FIRSTNAME>
<MIDDLENAME></MIDDLENAME>
</ROOT>
Then Sql stored it like
<ROOT>
<FIRSTNAME>ROGER</FIRSTNAME>
<MIDDLENAME />
</ROOT>
The sql update is just very simple:
UPDATE
SESIONESREPORTES
SET
SER_PARAMETROS = '
<ROOT>
<FIRSTNAME>ROGER</FIRSTNAME>
<MIDDLENAME></MIDDLENAME>
</ROOT>'
WHERE SER_ID=7
I need like this because I have some query that fails when a element is empty, you can see it here..
Merging many rows in a single
I don't think you can, looking at the following link:
XML Data Type and Columns
According to this (XML Storage Options Section):
The data is stored in an internal representation that preserves the
XML content of the data. This internal representation includes
information about the containment hierarchy, document order, and
element and attribute values. Specifically, the InfoSet content of the
XML data is preserved. For more information about InfoSet, visit
http://www.w3.org/TR/xml-infoset. The InfoSet content may not be an
identical copy of the text XML, because the following information is
not retained: insignificant white spaces, order of attributes,
namespace prefixes, and XML declaration.
So the internal storage will strip out all parts it deems unnecessary, the document goes on to state that if you need an exact copy of the XML document and not just the content, you should use either [n]varchar(max) or varbinary(max)
<MIDDLENAME></MIDDLENAME>
and
<MIDDLENAME/>
are equivalent; any XML parser will treat them identically - as an empty element. If your query fails on an empty element, it will fail on either of them. You'll need to either rewrite your query to handle empty elements, put some content in the <MIDDLENAME> element, or omit the element entirely (if your query can handle it's absence.)

SQL Server XML Value formatting newline

T-SQL XML value loses new line formats
I have XML file loaded into SQL server. I query this file to extract the nodes with value.
The problem is the new line characters are lost while selection. How to retain formatting so that when I display the text on the web, it not appear messy without line breaks.
See text and screenshots for details
T-SQL code:
declare #Text xml ;
set #Text= '<?xml version="1.0" encoding="utf-8"?>
<topic>
<L1>
<Subject>Subject text</Subject>
<Details>
Story Details are
This is paragraph
Text after After two line breaks
Text after After two line breaks
</Details>
</L1>
</topic>'
;with t as (select #Text [xmlcolumn])
--select * from t
SELECT x.a.value('(Subject)[1]','nvarchar(max)') as [Subject]
, x.a.value('(Details)[1]','nvarchar(max)') as [Details]
FROM t
cross apply
t.xmlcolumn.nodes('//L1') x(a)
Update: I misread your question - the problem with the newlines is purely in SQL Server Management Studio - it cannot represent those newlines. When you read your XML from an application in C# or VB.NET, those newlines will still be there - trust me.
But this original answer might also be relevant in other cases - you need to be aware that SQL Server is not storing your XML "as is" - it parses and converts it. So when you ask to get it back, it might look slightly different, but it's still the same XML functionally.
Yes, this is normal, expected behavior.
SQL Server stores your XML in a tokenized format - e.g. it doesn't store the actual, textual representation of your XML, but it parses and tokenizes your XML into XML fragments that are then stores inside this XML datatype.
Therefore, when you query it again, you'll get back a semantically correct and identical representation - but there's a possibility that certain textual representations are different.
E.g. when you pass in an empty XML element something like this:
<MyEmptyElement></MyEmptyElement>
you'll get back the "short" form of that when you retrieve the XML from SQL Server again:
<MyEmptyElement />
This is not the exact same text - but it's 100% the same XML from a semantic perspective.
As far as I know, you cannot influence this behavior in any way - you'll just have to live with it.

How to get the no of occurrences of element in xml data in sql server

In my xml i want to get the number of occurances of an element how can i do this.
for example in the below xml i want the number of times phone element is occuring
<Person>
<Name>abc</Name>
<Phone>1234</Phone>
<Phone>9876</Phone>
<Phone>5678</Phone>
</Person>
How can i achieve this ? Can someone help me .
declare #xml xml='<Person>
<Name>abc</Name>
<Phone>1234</Phone>
<Phone>9876</Phone>
<Phone>5678</Phone>
</Person>'
select #xml.value('count(//Person/Phone)','int')
You use XPATH. This site has a couple of examples of how to single out a specific type of node, by name. http://www.mycodeshare.com/item/1000000009/mssql-xml-query-using-xquery/
Start there and comment if it is not quite clear enough.

Resources