Mapping collection as a string to a target node - biztalk

I am using biztalk 2009 and need help with mapping. I have input like:
<root>
<shop>
<product>
<type>1</type>
<code>ab</code>
<desc></desc>
</product>
<product>
<type>2</type>
<code>cd</code>
<desc></desc>
</product>
</shop>
<address />
<names />
</root>
I want to map the collection of products to a target element as a string of xml that looks like this:
<products><product type="1" code="ab" /><product type="2" code="cd" /></products>
I have found a solution using custom xslt but I dont want to use it as we have found it to be very fickle. Is there any functoids that could do this for me with some custom scripting? I am also a c sharp dev thanks!

This is completely doable out of the box with a simple map.
Here is the soure XML file:
<root>
<shop>
<product>
<type>1</type>
<code>ab</code>
<desc></desc>
</product>
<product>
<type>2</type>
<code>cd</code>
<desc></desc>
</product>
</shop>
<address />
<names />
</root>
Here is the source schema:
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="shop">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="unbounded" name="product">
<xs:complexType>
<xs:sequence>
<xs:element name="type" type="xs:string" />
<xs:element name="code" type="xs:string" />
<xs:element name="desc" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="address">
<xs:complexType />
</xs:element>
<xs:element name="names">
<xs:complexType />
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Here is the target schema:
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="unbounded" name="product">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string" />
<xs:attribute name="code" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
And here is the map:
And here is the output:
<products>
<product type="1" code="ab" />
<product type="2" code="cd" />
</products>
Armed witht his result, you can follow one of two suggestions outlined by Mark Brimble in his blog.
How to copy the entire node to element of string type in a map

I am sorry to say this but when mapping gets too involved and there is no obvious way to do this in the mapper I just fall back on a .net helper method inside assign message which will build the output message.
The helper method can take a biztalk message as an argument of type XLANGMessage and return a type of XMLDocument which will be converted to your target message type, providing the xml inside renders the type correctly.
For example:
public static XmlDocument HelperMethod (XLANGMessage message)
{
var sourceType = (SourceType)message[0].RetrieveAs(typeof(SourceType));
var targetType = new TargetType();
// ... Do target type population and serialization to XmlDocument here
return targetAsXmlDoc;
}
It would be trivial to do this inside .net so just take it into .net and do it. Sorry to all the mapping gurus out there!

Related

BizTalk map not working when namespace prefix is missing

I can't get my BizTalk map to work with messages after envelope debatching. The map seems to require a namespace prefix but the debatched message doesn't have a prefix. If I add a prefix to the root, like this <ns0:Encounter xmlns:ns0="http://hl7.org/fhir/Encounters"> then the map works correctly when I use test map in visual studio. Without the prefix I still get an output from the map but only constants are mapped into the destination schema, nothing is mapped from the source schema.
I get the following error message for every mapped element
"error btm1044: Input validation error: The 'value' attribute is not declared."
I have tried changing the value of elementFormDefault from unqualified to qualified as suggested on a separate post but still no luck.
After envelope debatching I end up with the following XML. Note that there is no namespace prefix.
If I stop the Send Port and look at the debatched messages the MessageType is http://hl7.org/fhir/Encounters#Encounter .
<?xml version="1.0" encoding="utf-8"?>
<Encounter xmlns="http://hl7.org/fhir/Encounters">
<id value="ac34e2c2-6080-4c46-9ec5-d7340a7c4177" />
<extension url="https://api-foo.org/documents/fhir/extensions/encounter-facility">
<valueString value="foo" />
</extension>
<extension url="https://api-foo.org/documents/fhir/extensions/encounter-service">
<valueString value="fooo" />.......
My schema looks like this
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://hl7.org/fhir/Encounters" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://hl7.org/fhir/Encounters" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Encounter">
<xs:complexType>
<xs:sequence>
<xs:element name="id">
<xs:complexType>
<xs:attribute name="value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element maxOccurs="unbounded" name="extension">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="valueInteger">
<xs:complexType>
<xs:attribute name="value" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="valueString">
<xs:complexType>
<xs:attribute name="value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="url" type="xs:string" use="required" />
</xs:complexType>
</xs:element> ............
Is there a way to get the map/schema to work with the message as is, or a way to get the debatched message to have the prefix.
I also have a custom pipeline component to change the namespace of the incoming message before debatching. I'm not sure if this could be causing the issue the code is below.
public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
if (Enabled)
{
try
{
IBaseMessagePart bodyPart = inmsg.BodyPart;
if (bodyPart != null)
{
string json;
using (Stream originalDataStream = bodyPart.GetOriginalDataStream())
{
if (originalDataStream != null)
{
//Read the json message
using (TextReader tr = new StreamReader(originalDataStream))
{
json = tr.ReadToEnd();
}
//Use FHIR-NET-API to create a FHIR resource from the json
Hl7.Fhir.Serialization.ResourceReader resourceReader = new Hl7.Fhir.Serialization.ResourceReader(FhirJsonParser.CreateFhirReader(json), ParserSettings.Default);
//switch the namespace
var doc = XElement.Parse(Hl7.Fhir.Serialization.FhirSerializer.SerializeToXml(resourceReader.Deserialize()));
XNamespace toNs = Namespace;
doc.DescendantsAndSelf().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
var ele = doc.DescendantsAndSelf();
foreach (var el in ele)
el.Name = toNs + el.Name.LocalName;
//Create the new BizTalk message
var memoryStream = new MemoryStream();
doc.Save(memoryStream);
// memoryStream.Write(resourceXmlBytes, 0, resourceXmlBytes.Length);
memoryStream.Position = 0;
inmsg.BodyPart.Data = memoryStream;
}
}
}
return inmsg;
}
catch (Exception e)
{
GenericEventLogger.LogEvent(
ExceptionSource,
String.Format("An exception [{0}] occured in [{1}( )]. \n\nMessage: \n{2} \n\nStack Trace: \n{3}",
e.GetType().Name,
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName,
e.Message,
e.StackTrace),
EventLogEntryType.Error,
999);
throw;
}
}
return inmsg;
}
Here is the Envelope Schema
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://hl7.org/fhir/Encounters" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://hl7.org/fhir/Encounters" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:appinfo>
<b:schemaInfo is_envelope="yes" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" />
</xs:appinfo>
</xs:annotation>
<xs:element name="Bundle">
<xs:annotation>
<xs:appinfo>
<b:recordInfo body_xpath="/*[local-name()='Bundle' and namespace-uri()='http://hl7.org/fhir/Encounters']/*[local-name()='entry' and namespace-uri()='http://hl7.org/fhir/Encounters']/*[local-name()='resource' and namespace-uri()='http://hl7.org/fhir/Encounters']" />
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="total">
<xs:complexType>
<xs:attribute name="value" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
<xs:element maxOccurs="unbounded" name="entry">
<xs:complexType>
<xs:sequence>
<xs:element name="resource">
<xs:complexType>
<xs:sequence>
<xs:element name="Encounter">
<xs:complexType>
<xs:sequence>
<xs:any />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Since you're using the JSON representations of FHIR, the first question should be do you even need to use Xml Namespaces.
When working with native JSON content in BizTalk, my recommendation is to use the Empty Namespace in all Xml processing.
You can refer to this Wiki Article for more details: BizTalk: Simplify BizTalk Dev by Using the Empty Namespace

Can the Bundle.config include ScriptBundles?

Can I include scripts in my Bundle.config file, or is it only for style bundles?
<?xml version="1.0" encoding="utf-8" ?>
<bundles version="1.0">
<styleBundle path="~/Content/css">
...
</styleBundle>
<scriptBundle path="~/Scripts">
Is this possible?
</scriptBundle>
</bundles>
Also can anyone provide a link to a Bundle.config reference that explains the possible tags and structure? I've searched but all I can come up with is the BundleConfig.cs code way of bundling rather than the markup. I realise why - the markup way is older and maybe even deprecated. But I would like to learn the markup way as its common I will be working with legacy systems that use the older method.
This is called a "bundle manifest". This is an XML file located at ~/bundle.config and loaded through BundleManifest.ReadBundleManifest(); in your Application_Start.
There is an XSD in CodePlex, named BundleManifestSchema.xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="BundleConfig" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="include">
<xs:attribute name="path" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="styleBundle">
<xs:sequence>
<xs:element name="include" type="include" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="path" type="xs:string" use="required" />
<xs:attribute name="cdnPath" type="xs:string" use="optional" />
</xs:complexType>
<xs:complexType name="scriptBundle">
<xs:sequence>
<xs:element name="include" type="include" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="path" type="xs:string" use="required" />
<xs:attribute name="cdnPath" type="xs:string" use="optional" />
<xs:attribute name="cdnFallbackExpression" type="xs:string" use="optional" />
</xs:complexType>
<xs:element name="bundles">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element type="styleBundle" name="styleBundle" />
<xs:element type="scriptBundle" name="scriptBundle" />
</xs:choice>
<xs:attribute name="version" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>
So yes, scriptBundle is supported.
I don't think it's possible and I think you should really avoid using the XML notation. There are almost no resources regarding that topic on the web. So it might be faster to just rewrite the XML to C#. However, there is a NuGet package that will allow you to configure it via XML. The example can be found on GitHub and on the project site.

Mass Changing Image in Crystal Reports

I want to change an image in about 110 CR 2008 Reports.
I've seen answer about mass changing fields, but I need to change image.
Is their any script or method I could use ?
if you are saving the image in the database you can create schema xml file to reade from the image from DB and call this schema as subreport in the report itself.
the schema will be like this:
You have to make some modification on the id, target, element(table Name) and source as your requirements.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="rptAppSettings" targetNamespace="http://tempuri.org/AppSettings.xsd" xmlns:mstns="http://tempuri.org/AppSettings.xsd" xmlns="http://tempuri.org /AppSettings.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas- microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:annotation>
<xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource">
<DataSource DefaultConnectionIndex="0" FunctionsComponentName="QueriesTableAdapter" Modifier="AutoLayout, AnsiClass, Class, Public" SchemaSerializationMode="IncludeSchema" xmlns="urn:schemas-microsoft- com:xml-msdatasource">
<Connections>
<Connection AppSettingsObjectName="Web.config" AppSettingsPropertyName="ConnectionString" IsAppSettingsProperty="true" Modifier="Assembly" Name="ConnectionString (Web.config)" ParameterPrefix="#" PropertyReference="AppConfig.System.Configuration.ConfigurationManager.0.ConnectionStrings.ConnectionString.ConnectionString" Provider="System.Data.SqlClient" />
</Connections>
<Tables />
<Sources />
</DataSource>
</xs:appinfo>
</xs:annotation>
<xs:element name="rptAppSettings" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_DataSetName="rptAppSettings" msprop:Generator_UserDSName="rptAppSettings">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="App_Settings" msprop:Generator_UserTableName="App_Settings" msprop:Generator_RowEvArgName="App_SettingsRowChangeEvent" msprop:Generator_TableVarName="tableApp_Settings" msprop:Generator_TablePropName="App_Settings" msprop:Generator_RowDeletingName="App_SettingsRowDeleting" msprop:Generator_RowChangingName="App_SettingsRowChanging" msprop:Generator_RowDeletedName="App_SettingsRowDeleted" msprop:Generator_TableClassName="App_SettingsDataTable" msprop:Generator_RowChangedName="App_SettingsRowChanged" msprop:Generator_RowEvHandlerName="App_SettingsRowChangeEventHandler" msprop:Generator_RowClassName="App_SettingsRow">
<xs:complexType>
<xs:sequence>
<xs:element name="LogoImage" msprop:Generator_ColumnVarNameInTable="columnLogoImage" msprop:Generator_ColumnPropNameInRow="LogoImage" msprop:Generator_ColumnPropNameInTable="LogoImageColumn" msprop:Generator_UserColumnName="LogoImage" type="xs:base64Binary" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>

BizTalk 2010 Map destination message show all nodes

I have a source schema with less elements than the destination schema. When I run the map only mapped elements in destination schema shows up. I want all the elements in destination schema to show up, even they are empty. How to do this?
Set the "Default Value" of the output schema. This will create empty nodes.
The most convenient way is to use Inline C# Scripting functoid for this.
Scripting functoid:
public string GetEmptyString()
{
return System.String.Empty;
}
You can just link this functoid to all output nodes where you wish to see empty node.
Example:
Input schema:
<xs:schema xmlns="http://person" targetNamespace="http://person" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string" />
<xs:element name="Surname" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Output schema:
<xs:schema xmlns="http://employee"
targetNamespace="http://employee"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="MidName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
<xs:element name="Age" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Input message:
<ns0:Person xmlns:ns0="http://person">
<Name>John</Name>
<Surname>Snow</Surname>
</ns0:Person>
Expected output message:
<ns0:Employee xmlns:ns0="http://employee">
<FirstName>John</FirstName>
<MidName />
<LastName>Snow</LastName>
<Age />
</ns0:Employee>
Solution:
Link Person.Name to Employee.FirstName
Link Person.Surname to Employee.LastName
Create Scripting functoid that returns empty string
Link Scripting functoid to Employee.MidName
Link Scripting functoid to Employee.Age

ASP.net parsing Diffgrams in XML to use in DataList

I have a method:
public static DataSet getTable()
{
DataSet DS = new DataSet("My Set");
DS.ReadXml(getCategories());
return DS;
}
My getCategories() returns a stream containing my XML.
But when I run this, I get this error:
The supplied xml instance is a schema or contains an inline schema. This class cannot infer a schema for a schema.
So I'm not sure what to do.
My goal is to use the call to getTable() to populate a DataList.
I've tried using the DataTable and I get a different, but similar error.
Any help would be great.
Thanks.
Here is my XML file. Might help. Thanks.
<?xml version="1.0" encoding="utf-8"?>
<WSPackage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<ResponseInteger>0</ResponseInteger>
<ResponseBoolean>false</ResponseBoolean>
<ResponseDataset>
<xs:schema id="CategoryDS" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="CategoryDS" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Category">
<xs:complexType>
<xs:sequence>
<xs:element name="PartCategories" type="xs:string" minOccurs="0" />
<xs:element name="CategoryDescriptions" type="xs:string" minOccurs="0" />
<xs:element name="CategoryImageURLs" type="xs:string" minOccurs="0" />
<xs:element name="CategoryModelFlags" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<CategoryDS xmlns="">
<Category diffgr:id="Category1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<PartCategories>TESTCAT</PartCategories>
<CategoryDescriptions>TESTING API</CategoryDescriptions>
<CategoryImageURLs />
<CategoryModelFlags />
</Category>
</CategoryDS>
</diffgr:diffgram>
</ResponseDataset>
<ErrorMessage />
<UserMessage />
</WSPackage>
It is related to the fact that you have the following xml in there.. If you take that out it should work. it is not going to create a schema for something that already exists.
<xs:element name="Category">
<xs:complexType>
<xs:sequence>
<xs:element name="PartCategories" type="xs:string" minOccurs="0" />
<xs:element name="CategoryDescriptions" type="xs:string" minOccurs="0" />
<xs:element name="CategoryImageURLs" type="xs:string" minOccurs="0" />
<xs:element name="CategoryModelFlags" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
t

Resources