map single source schema element to multiple element with attribute - biztalk

I have a source schema as follows:
Users
Id
Name
Department
and destination schema as follows:
Employee
Name
Number
number_type(attribute)
I need to do the following mapping
Name ---> Name
Id ---> Number (number_type = "Id")
Department_no --> Number (number_type = "dept")
I need to map both Id and department number i.e. 2 elements to 1 element i.e. Number in dest schema but for both attribute value should be different.
Input
<Users>
<Id>123</Id>
<Name>abc</Name>
<Department_no>456</Department_no>
</Users>
Output:
<Employee>
<Name>abc</Name>
<Number number_type = "Id">123</Number>
<Number number_type = "dept">456</Number>
</Employee>
How can I achieve in BizTalk or what could be the inline XSLT for the same?

You nearly have it
Name ---> Name
Id ---> Number
Department --> Number
Then also link both Id & Department to a looping functoid that goes to Number
Plus to do the attributes there are some things you can try such as
Id ---> number_type
Department --> number_type
But click on the links select Copy Name instead of the Copy Text value.
From an input
<ns0:Root xmlns:ns0="http://Scratch.SO55049939Input">
<Users>
<Id>Id_0</Id>
<Name>Name_0</Name>
<Department>Department_0</Department>
</Users>
</ns0:Root>
You will get output
<ns0:Root xmlns:ns0="http://Scratch.SO55049939output">
<Employee>
<Name>Name_0</Name>
<Number number_type="Id">Id_0</Number>
<Number number_type="Department">Department_0</Number>
</Employee>
</ns0:Root>

Related

ORA-19279 XPTY0004 - Xquery dynamic type mismatch: expected singleton sequence - got multi-item sequence

I have next below xml message in CLOB column:
<Message type="Close Subscription" creationdatetime="15/01/2010 07:48" market="01" xmlns="http://test.org/">
<Customer userId="data" market="01">
<UserAccount>test#hotmail.com</UserAccount>
<ExpireDate>15/02/2016 07:48:11</ExpireDate>
<Member>
<MemberReferency number="000003" digit="85" market="01" name="John Rambo"/>
</Member>
<Email Id="700">
<Address>test#hotmail.com</Address>
<IsConfirmed>True</IsConfirmed>
<Privacies>
<Privacy type="C" value="I"/>
<Privacy type="M" value="I"/>
</Privacies>
</Email>
<Newsletter mailService="NL">
<language>N</language>
<frequency>0</frequency>
<promotion/>
<origin/>
</Newsletter>
</Customer>
</Message>
For this xml message, I have twice the xml tag privacy
<Privacies>
<Privacy type="C" value="I"/>
<Privacy type="M" value="T"/>
</Privacies>
How can I get the value of privacy for only one of them without fetch the error?.
I mean, to get the privacy of the type='C'.
Now I'm using next below query that contain the error:
select Privacy
from (select *
from ta_gen.notification_log a,
XMLTable(XMLNAMESPACES('http://test.org/' AS "XML"),
'/XML:Message' passing xmltype(NTL_MSG) columns
Privacy VARCHAR2(1) path 'XML:Customer/XML:Email/XML:Privacies/XML:Privacy/#value') O
where a.ntl_type = 'Message')
NOTE: When the xml tag privacy is once in the xml message, the error is not raised.
Depending on what you want to happen when there is only an M-type node, you canb either search explicitly for the type attribute being C:
select x.privacy
from notification_log a
cross join XMLTable(XMLNamespaces('http://test.org/' AS "XML"),
'/XML:Message'
passing XMLType(ntl_msg)
columns privacy varchar2(1)
path 'XML:Customer/XML:Email/XML:Privacies/XML:Privacy[#type="C"]/#value') x
where a.ntl_type = 'Message';
PRIVACY
-------
I
Or you can extract the type and value for all privacy nodes via a second level of XMLTable, and then decide which to keep:
select min(x2.privacy) keep (dense_rank first order by x2.type) as privacy
from notification_log a
cross join XMLTable(XMLNamespaces('http://test.org/' AS "XML"),
'/XML:Message' passing XMLType(ntl_msg)
columns privacies XMLType path 'XML:Customer/XML:Email/XML:Privacies') x1
cross join XMLTable(XMLNAMESPACES('http://test.org/' AS "XML"),
'XML:Privacies/XML:Privacy'
passing privacies
columns type varchar2(1) path '#type',
privacy varchar2(1) path '#value') x2
where a.ntl_type = 'Message';
PRIVACY
-------
I
If you ran the same query but instead did select x2.type, x2.value from ... then you'd see:
TYPE PRIVACY
---- -------
C I
M I
.. and the min(x2.privacy) keep (dense_rank first order by x2.type) gets the value type from the 'lower' (according to string comparison) type value; which means it prioritises C over M if both exist, but will use either if there is only one

XQuery - to insert splitted nodes data into another node

<?xml version="1.0" encoding="UTF-8"?>
<Data>
<A><DelInfo>123-20150308-345</DelInfo><OrderNo>11</OrderNo></A>
<A><DelInfo>1204-20150308-355</DelInfo><OrderNo>15</OrderNo></A>
<A><DelInfo>153-20150408-343</DelInfo><OrderNo>10</OrderNo></A>
<A><DelInfo>44345-20150308-341</DelInfo><OrderNo>21</OrderNo></A>
<A><DelInfo>153-20150204-245</DelInfo><OrderNo>1</OrderNo></A>
<A><DelInfo>423-20150311-445</DelInfo><OrderNo>13</OrderNo></A>
..........
</Data>
I receive following XML. The DelInfo node contains a combination of
EmpId, Delivery Date and Receipt No. The OrderNo node contains the
order number wrt the Delivery Information.
The XML is stored in BaseX and I need following report to be generated from the
above XML.
<A><DelInfo>123-20150308-345</DelInfo><OrderNo>11</OrderNo><Report>20150308 - 11</Report></A>
.....
In other word, I want to insert an additional node Report with Date and Order No.
Any idea?
Replace yourdoc with your document name.
for $x in doc('yourdoc')//A
let $d := substring-before(substring-after($x/DelInfo, "-"), "-")
let $o := $x/OrderNo/text()
let $i := <C>{concat($d, " - ", $o)}</C>
return
insert node $i after $x/OrderNo
The inner substring-after() will return the string after the first -. Then, the substring-before() will return the string before the -. This way you will get the Date portion.

How to create XML file by SQL query?

I have a Select query which selects the top 10 values from table
Create proc [dbo].[SP_Select_Top10]
as
select DISTINCT top (10)
Score, FBid
from
FB_Player
ORDER BY
Score DESC
What I need is to have the results of this query in xml file as.
<player>
<name> </name>
<score> </score>
</player>
I use ASP.NET to create this file how can I do that ?
Create your stored procedure like this - use the FOR XML PATH(), ROOT() syntax to have SQL Server generate a proper XML for you:
CREATE PROCEDURE dbo.procGetPlayerScore
AS BEGIN
SELECT DISTINCT TOP (10)
ID AS '#ID', -- creates an attribute on the <Player> node
Name, -- gets output as element inside <Player>
Score -- gets output as element inside <Player>
FROM
dbo.FB_Players
ORDER BY
Score DESC
FOR XML PATH('Player'), ROOT('AllPlayers')
END
In your C# code, you need something like this - connect to the database, execute the stored procedure, get back the single row, single column of that stored procedure (the XML produced):
// set up SQL Server connection and command to execute the stored procedure
using(SqlConnection conn = new SqlConnection("server=.;database=test;Integrated Security=SSPI"))
using (SqlCommand cmdGetPlayers = new SqlCommand("dbo.procGetPlayerScore", conn))
{
// define that it's a stored procedure
cmdGetPlayers.CommandType = CommandType.StoredProcedure;
// open connection, execute procedure, get resulting XML, close connection
conn.Open();
string playersXml = cmdGetPlayers.ExecuteScalar().ToString();
conn.Close();
}
As result, you'll get a XML something like this:
<AllPlayers>
<Player ID="4">
<Name>Player 4</Name>
<Score>72.1500</Score>
</Player>
<Player ID="1">
<Name>Player 1</Name>
<Score>50.5000</Score>
</Player>
......
</AllPlayers>
I would suggest looking at the native XML options of SQL Server
Link here
Also please note
<player>
<playername="" score="" />
</player>
is not valid xml, it would have to something like
<player name="" score="" />
or
<player>
<name></name>
<score></score>
</player>
depending on whether you want to be element-centric or attribute-centric, but all of these can be specified in the SQL server XML output options. Then you could just get the ASP.NET side to save the resulting query as a file.

XQuery : OBJECT_VALUE invalid identifier

I've created a table
Movie ( title varchar2(40), review XMLTYPE)
And review has: `
<review>
<reviewer>...</reviewer>
<title> ....</title>
<rating>.....</rating> </Review> </reviewer>
When I try to access :
SELECT X.reviewername FROM movie m, XMLTABLE ('for $d in /reviews/review
return $d'
PASSING OBJECT_VALUE
columns
reviewername VARCHAR2(50) PATH 'reviewer') AS X
I get an error at OBJECT_VALUE. Where am I going wrong?
EDIT: I changed the Query to
SELECT m.title,
warehouse2.*
FROM movie M,
XMLTABLE('/REVIEW'
PASSING m.reviews
COLUMNS
"Rail" varchar2(60) PATH '//RATING')
warehouse2;
But no rows are getting selected. Any suggestions?
Well for one thing, don't you have a typo: '/reviews/review ' ? there is no element called anywhere in your example.
Your XML isn't well formed, you have overlapping tags, you have mismatched reviews/Reviews (XML is case sensitive) and in your query you have reviews/review but your xml has /review (no s on the end). –

Query to output content of AllXml column of ELMAH_Error sql server table

I am having trouble writing query so that I can query the content of AllXml column inside Elmah_Error table.
How can I list out all the item nodes as an output of the query.
How could I write query to only list for certain item nodes?
I would like to get follow resultset:
item value
===== =====
ALL_HTTP HTTP_CONNECTION:xxxx
ALL_RAW Connection: xxxxx
I would also like to be able to filter the query by ErrorID
Content of AllXml column may look like this.
<error
application="/"
message="hello world"
source="TestWebElmah"
detail="xxxxx">
<serverVariables>
<item
name="ALL_HTTP">
<value
string="HTTP_CONNECTION:xxxx" />
</item>
<item
name="ALL_RAW">
<value
string="Connection: xxxxx" />
</item>
</serverVariables>
</error>
Remote Addr nodes
select T.N.value('(value/#string)[1]', 'varchar(30)') as REMOTE_ADDR
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error) e
cross apply AllXml.nodes('//item[#name="REMOTE_ADDR"]') as T(N)
HTTP User Agents which contain mozilla
select T.N.value('(value/#string)[1]', 'varchar(30)') as HTTP_USER_AGENT
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error) e
cross apply AllXml.nodes('//item[#name="HTTP_USER_AGENT"]') as T(N)
where T.N.value('(value/#string)[1]', 'varchar(30)') like '%mozilla%'
Elmah table stores the AllXml column as nvarchar so it needs to be casted to xml
all tags + values, by error id
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error where ErrorId = 'DC82172B-F2C0-48CE-8621-A60B702ECF93') e
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
Before voting down this answer, because uses most of the part of Mikael Eriksson's answer, I let you know I'll happily accept the downvotes only for this reason, since is mainly true
This query will give you all item nodes
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from Elmah_Error
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
If you want to filter on any of the values you can put that in a sub-query apply a regular where clause.
select Name,
Value
from
(
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from Elmah_Error
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
) T
where Name = 'ALL_HTTP'

Resources