BizTalk 2013 Getting xml content in map - biztalk

How can I get the XML context (the entire Msg) using a map, from the source schema, and pass it to an element field in the destination schema?
Scenario Description: The Msg was previously received (already in MsgBox). The map is located in a SendPort of type WFC-Custom with SqlBinding. The idea is to storage the entire XML Msg into a Database table field of type XML.
I'm not using any Orchestration on this application, on BizTalk 2013 R2.

you can use a script functoid and write a inline xslt like below
<xsl:element name="tgtXml">
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:copy-of select="/" />
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:element>

Related

how to save payload of soa composite to xml file?

i am working on oracle SOA project in which i want to save csv data to XML file. till now i got the payload in form of xml using Translate activity but i can only use it directly. I want to save the pay load to xml file.
i am facing following error :
<?xml version="1.0" encoding="UTF-8"?><bpelFault>
<faultType>0</faultType>
<subLanguageExecutionFault xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable">
<part name="summary">
<summary>An error occurs while processing the XPath expression; the expression is ora:doXSLTransformForDoc("../Transformations/Transformation.xsl", $Receive_Read_InputVariable.body)</summary>
</part>
<part name="code">
<code>XPath expression failed to execute</code>
</part>
<part name="detail">
<detail>XPath expression failed to execute.
An error occurs while processing the XPath expression; the expression is ora:doXSLTransformForDoc("../Transformations/Transformation.xsl", $Receive_Read_InputVariable.body)
The XPath expression failed to execute; the reason was: javax.xml.transform.TransformerException: oramds:/deployed-composites/default/CSV_To_XML_rev1.0/Transformations/Transformation.xsl<Line 30, Column 109>: XML-22031: (Error) Variable not defined: 'oracle_empty_param'.
Check the detailed root cause described in the exception message text and verify that the XPath query is correct.
</detail>
</part>
</subLanguageExecutionFault>
</bpelFault>
I am working with oracle soa suite 12c.
It sounds like you want to convert a variable to a string. I would use an XSL transform. Input to the transform would be your newly translated variable and the output be a plain old String variable. The transform would look like this:
<xsl:template match="/">
<tns:myString>
<xsl:copy-of select="/ns0:RootElement"/>
</tns:myString>
</xsl:template>
If you wanted to, you could then write this string to the file adapter

Logical Existence doesn't work - BizTalk Mapper

This problem has confounded me for a while now. I have a flat file with segments and tag identifiers. One of the segments is optional. That is fine, but i need logic to determine if this segment exists. If it does not exist i need to do something else. All works as planned if the segment exists. If it doesn't, it appears BizTalk does not even recognize or execute any functoids related to the segment.
Here is the flat file segment:
And here is my Logical Existence connected to a Logical NOT:
Again, if the segment is completely gone (meaning no flat file xml nodes are created/translated), the Logical Existence does not even execute. I've tried scripts, functoids. I'm becoming convinced this is a bug in the mapper. Any help appreciated.
Try using the Value Mapping functoid instead of the Value Mapping (Flattening) functoid.
Also ensure that the parameters of the Value Mapping functoids are in the correct order. The logical operator must be the first parameter. Sometimes the parameters go out of order and the functoid stops working as expected.
Since your input file is a flat file, the FFDASM is creating an empty node. The test run by Logical Existence evaluates to true on an empty node. Logical String should work here (I was previously thinking it would return true for an empty string but it shouldn't).
However, in this case, I'd probably replace all of that (including the value mapper) with a C# scripting functoid:
public string AllowIfNotEmpty(string test, string output)
{
if (!string.IsNullOrWhiteSpace(test))
return output;
return "";
}
Give it the input of the node currently linked to Logical String first, and the second input to your Value Mapping(flattening) second, and output it directly to your destination node.
You could put that into a helper assembly if it's something you use in multiple places.
If you wanted to keep it as XSLT, you could do a custom call template:
<xsl:template name="OutputIfNotEmpty">
<xsl:param name="test" />
<xsl:param name="output" />
<xsl:if test="normalize-space($test) != ''">
<xsl:element name="OutputElementName">
<xsl:value-of select="$output" />
</xsl:element>
</xsl:if>
</xsl:template>

How do I pivot XML nodes to XML rows?

I have an XML file which has hard-coded element names such as FIRST_NAME, LAST_NAME etc.
<employee>
<EMP_NO>1234</EMP_NO>
<FIRST_NAME>Bob</FIRST_NAME>
<SOMETHING_ELSE>Weakly mapped</SOMETHING_ELSE>
<SOME_OTHER_VALUE>Also weakly mapped</SOME_OTHER_VALUE>
<LAST_NAME>Smith</LAST_NAME>
</employee>
The output I am after is
<employee>
<number>123</number>
<values>
<value>
<name>FIRST_NAME</name>
<value>Bob</value>
</value>
<value>
<name>LAST_NAME</name>
<value>Smith</value>
</value>
<value>
<name>SOMETHING_ELSE</name>
<value>Weakly mapped</value>
</value>
<value>
<name>SOME_OTHER_VALUE</name>
<value>Also weakly mapped</value>
</value>
</value>
</employee>
Some of these nodes are expected, emp_no, first_name and last_name and I will create explicit mapping from the XML source to the XML dest for those nodes to match the input.
What I need to achieve next is for every unmapped node to also add items to my target XML. If a new node comes in then it will also be added to the target XML.
If this is not possible then I'd just like a quick way of manually selecting nodes and transforming them into items, otherwise I am going to have to spend hours manually adding nodes in the target and wiring up the name (constant) and value from the source node.
This is the kind of thing I am having to do now...
Obviously for hundreds of nodes this is going to take me hours, and I have a number of files to create mappings for so it will take me days. I'd really like at least to be able to do something like this...
It is possible to do what you want in MapForce with a custom, imported inline xsl template, and a slight modification to your range schema. It is a bit of a hack to do this in MapForce, and it is probably easier and cleaner to use a hand-written xsl transform instead.
Start with the custom template (in a file, e.g. custom.xsl):
<xsl:template name="metaItemIterate">
<xsl:param name="employeeNode"/>
<xsl:for-each select="$employeeNode/*">
<xsl:element name="metaItem">
<xsl:element name="name">
<xsl:value-of select="local-name(.)"/>
</xsl:element>
<xsl:element name="value">
<xsl:value-of select="."/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:template>
Note that this template generates a single element with multiple children. You could alternatively just generate the necessary child elements, and link them accordingly...
Then use the Add/Remove Libraries... button (found below the Libraries) to add your xsl file as a library.
Drag the new function between the range and domain schemas, and connect the employee node to employeeNode and the result of the function to clientDefinedMetaData.
Note you may need to add the attribute mixed="true" to the schema definition for clientDefinedMetaData in order to allow generation of random elements below it.
The output I get with your data from clicking the Output tab:
Also, if you cannot change the schema definition to allow the mixed elements below it, it is probably not possible to go about this any other way with MapForce.

BizTalk HIPAA EDI multi-input map doesn't generate node

I had asked this question 2 years ago (Problem with BizTalk multi-input map), but then the project was shelved and I never did any further testing. I'm having to dust it off again, with some more details and screenshots.
I have a BizTalk HIPAA solution that needs to merge an 837 claim schema with some data from our system. We're doing this with a map that has two input schemas, as shown here:
(I've greatly simplified the schemas for testing purposes).
The accepted answer to my original post (using an equal functoid and value mappers) works fine with a simple schema like I had originally shown, but fails with the actual EDI schema.
In the first input message, if IsRepriced = 1, I want to use our values for HCP_01, HCP_02, and HCP_03. If it's 0, use the values in the second message (the original 837 claim). The functoids shown work fine as long as the original 837 claim actually contains the HCP node (segment), but if it's not there I'm unable to generate one from our data.
Replacing these with a scripting functoid using some if-then-else C# code has the same effect.
So, is there a way to do this using functoids, or do I need to resort to XSLT? Unfortunately I know next to nothing about XSLT, so that's going to be difficult...
Thanks!
Edit: I would up using an Inline XSLT Call Template, with this code:
<xsl:template name="Repricing_2000B_HCP">
<xsl:param name="IsRepriced" />
<xsl:choose>
<xsl:when test="$IsRepriced='1'">
<xsl:for-each select="//InputMessagePart_1/ns0:X12_00401_837_I/ns0:TS837Q3_2000A_Loop/ns0:TS837Q3_2000B_Loop/ns0:TS837Q3_2300_Loop/ns0:HCP_ClaimPricingRepricingInformation_TS837Q3_2300">
<xsl:element name="ns0:HCP_ClaimPricingRepricingInformation_TS837Q3_2300">
<xsl:copy-of select="./#*" />
<xsl:copy-of select="./*" />
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="//InputMessagePart_0/ns0:X12_00401_837_I/ns0:TS837Q3_2000A_Loop/ns0:TS837Q3_2000B_Loop/ns0:TS837Q3_2300_Loop/ns0:HCP_ClaimPricingRepricingInformation_TS837Q3_2300">
<xsl:element name="ns0:HCP_ClaimPricingRepricingInformation_TS837Q3_2300">
<xsl:copy-of select="./#*" />
<xsl:copy-of select="./*" />
</xsl:element>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I frequently hit a brick wall with with the if missing-else paradign in a Map. Sometimes Looping Functioids do the trick, sometimes not. Sometimes a carefully placed Logical Existence -> Not works, sometimes no.
It's mostly because if one of the source Records is minOccurs=0, the Mapper will wrap everything in a for-each. Since the Element doesn't exist, the code never gets executed.
I'd say >50%, I resort to inline Xslt because at some point, it becomes cleaner than a page of mostly duplicate Functoid groups.
However, I'd bet the Xslt won't turn out as difficult a proposition as you think. The Mapper can do most of the work for you. You can build the bulk of the Map using Functoids, then just copy the resulting Xslt. You will have to modify for some things, like namespaces.
(Same answer)

BizTalk force empty elements to be created without using xslt call template

Is there anyway in a BizTalk map to force destination elements to be created when the source elements don't exist without using an xslt call template?
I'm mapping parent/child xml to a wcf-sql adapter generated schema that has table-valued parameters for stored proc parameters.
So my source xml is:
<Category>
<CategoryId>1</CategoryId>
<CategoryName>Test</CategoryName>
</Category>
and/or a Category with Media
<Category>
<CategoryId>1</CategoryId>
<CategoryName>Test</CategoryName>
<Media>
<Medium>
<MediumId>1</MediumId>
<MediumName>test.jpg</MediumName>
</Medium>
</Media>
</Category>
The schema for the TypedProcedure is something like:
<ImportCategoryRequest>
<Category>
<CategoryId>1</CategoryId>
<CategoryName>Test</CategoryName>
</Category>
<Media>
<Medium>
<MediumId>1</MediumId>
<MediumName>test.jpg</MediumName>
</Medium>
</Media>
</ImportCategoryRequest>
So it doesn't like it when is all that shows up in the destination XML. Instead of passing null for a table-valued parameter it wants at least 1 row and to pass null values for the columns in the tvp. I can create the dummy xml with a xslt call-template but I'd like to avoid that.
The BizTalk mapper seems to use <xsl:for-each> and as a result won't generate an output element if there is no input.
But using xslt is really easy - see here how to scrape the xslt out of your existing map (and just remove the escaping around double quotes and slashes), and to change the map to custom XSLT.
The bit you need to change is around the Media is something like:
<xsl:choose>
<xsl:when test="count(ns0:Media)!=0">
<!-- Copy the mapper generated XSLT in the for each here-->
<xsl:foreach >
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<Media>
<Medium>
<MediumId>1</MediumId>
<MediumName>test.jpg</MediumName>
</Medium>
</Media>
</xsl:otherwise>
</xsl:choose>

Resources