Build SOAP envelope with XDocument instead of string - c#

currently I have this code to build a soap envelope:
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body> " +
"<ABRSearchByABN xmlns=\"http://abr.business.gov.au/ABRXMLSearch/\"> " +
"<searchString>" + searchValue + "</searchString>" +
"<includeHistoricalDetails>" + history + "</includeHistoricalDetails>" +
"<authenticationGuid>" + guid + "</authenticationGuid>" +
"</ABRSearchByABN>" +
"</soap:Body>" +
"</soap:Envelope>";
I am trying to create an XML document instead but I am not sure on how to go on with the namespaces.
Code that obiously doesn't work:
XNamespace soap = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xmlns = "http://abr.business.gov.au/ABRXMLSearch/";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
XDocument xd = new XDocument(
new XDeclaration("1.0","utf-8",""),
new XElement("soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"",
new XElement("soap:Body",
new XElement("ABRSearchByABN xmlns=\"http://abr.business.gov.au/ABRXMLSearch/\"",
new XElement("searchString", searchValue),
new XElement("includeHistoricalDetails", history),
new XElement("authenticationGuid", guid)))));
How can I complete this?
Thanks in advance.

You could use the XmlDocument class and continue to append children.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.AppendChild(xmlDoc.CreateNode(XmlNodeType.Element, "soap", "Envelope", "http://www.w3.org/2001/XMLSchema-instance"));
Also, assuming you already have your xml stored as a string, an even simpler although potentially less manageable solution would be to simply declare a new XmlDocument and load the string to it.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(yourString);

This covers everything in pretty good detail: http://msdn.microsoft.com/en-us/library/bb387042.aspx
You can't think of a DOM API (like L2XML or XmlDocument) the same way as you think of your string-concatenating code. When working with L2XML, namespace declarations and attributes are "things" that need to be handled explicitly, not just extra characters that go between angle brackets. Consequently, the XElement constructor isn't as simple as "here is the string I want to go between the angle brackets." Instead, you need to use an alternate XElement constructor that handles namespaces.

Related

Error when redefining a different xml Namespace to an existing alias using XElement with System.Xml.Linq

I try programming the following xml document (simplified) as code:
<P xmlns="http://schemas.microsoft.com/x/2010/manifest"
xmlns:ab="http://schemas.microsoft.com/a/2010/manifest"
xmlns:ac="http://schemas.microsoft.com/a/2013/manifest">
<ab:Ex xmlns:ab="http://schemas.microsoft.com/a/2013/manifest">
</ab:Ex>
</P>
Now an element redefines the namespace:
xmlns:ab="http://schemas.microsoft.com/a/2013/manifest".
how do I get the element into my program? It is obviously valid because I can load the xml file like this:
Add(new XAttribute (XNamespace.Xmlns + "ab")
I get the error message:
System.Xml.XmlException: 'The prefix 'ab' cannot be redefined from 'http://schemas.microsoft.com/a/2010/manifest' to 'http://schemas.microsoft.com/a/2013/manifest' within the same start element tag.'
Actually logical (redefinition) but when I load the document, the element is accepted.
using System.Xml.Linq;
namespace xmltest
{
class Program
{
static void Main(string[] args)
{
//Load
XDocument doc1 = XDocument.Load(#"c:\simple.xml", LoadOptions.None);
System.Console.WriteLine(doc1.ToString());
//Create new
XNamespace ab = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace nsx = "http://schemas.microsoft.com/x/2010/manifest";
XDocument doc2 = new XDocument(new XDeclaration("1.0", "utf-8", ""),
new XElement(nsx + "P"));
doc2.Element(nsx + "P").Add(new XAttribute("xmlns",
"http://schemas.microsoft.com/x/2010/manifest"));
doc2.Element(nsx + "P").Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2010/manifest"));
doc2.Element(nsx + "P").Add(new XAttribute(XNamespace.Xmlns + "ac",
"http://schemas.microsoft.com/a/2013/manifest"));
XElement xml = new XElement(ab + "Ex");
//--> Below does not work work
xml.Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2013/manifest"));
doc2.Element(nsx + "P").Add(xml);
System.Console.WriteLine(doc2.ToString());
}
}
}
Anybody have any idea how to solve this problem?
In theory, because
<ab:Ex xmlns:ab="http://schemas.microsoft.com/a/2013/manifest">
actually means that Ex is to be defined in the new namespace (2013), you can get what you want by defining Ex in the new namespace, i.e. something like:
XNamespace abOld = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace abNew = "http://schemas.microsoft.com/a/2013/manifest";
XNamespace nsx = ...
XElement xml = new XElement(abNew + "Ex");
xml.Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2013/manifest"));
However, repurposing the alias of an existing namespace just so that you can use the same alias is going to be really confusing to future maintenance - as the alias leaves scope, it will revert to it's old definition. I would recommend that you at least create different, unique aliases for the 2010 and 2013 namespaces.
Also, unless the intended consumer of the Xml was buggy, and required specific aliases or namespace scopes, I would generally avoid micro-managing the namespace aliasing and namespace scoping - let Linq to Xml manage that for you.
For instance, how about just:
XNamespace abOld = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace abNew = "http://schemas.microsoft.com/a/2013/manifest";
// Build up the document by providing element, attribute + applicable namespaces:
var root = new XElement(abOld + "P",
new XElement(abNew + "Ex"));

Add xsi:type to my XML document

I have a code to extract an XML document type using this web service method
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XAttribute attribute = new XAttribute(xsi + "type", "xsd:string");
XElement node_user_id = new XElement("user_id", attribute, user.code);
XDocument doc = new XDocument(new XElement("ranzcp_user", new XAttribute(XNamespace.Xmlns + "ns1", "urn:logon"), node_user_id));
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(elem.ToString());
With the above code i was able to extract an xml document exactly like this :
<ranzcp_user xmlns:ns1="urn:logon">
<user_id xmlns:p3="http://www.w3.org/2001/XMLSchema-instance" p3:type="xsd:string">12345678</user_id>
</ranzcp_user>
But what i really need to have is this :
<ranzcp_user xmlns:ns1="urn:logon">
<user_id xsi:type="xsd:string">12345678</user_id>
</ranzcp_user>
Is there any way i could get the format i need for the xml, and second do the xsi:type="xsd:string" attribute was neccessary when the xml data was parsed?
TIA!
You could explicitly define the namespace prefix so you use the canonical xsi rather than p3:
var doc = new XDocument(
new XElement("ranzcp_user",
new XAttribute(XNamespace.Xmlns + "ns1", "urn:logon"),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement("user_id", 12345678,
new XAttribute(xsi + "type", "xsd:string")
)
)
);
See this fiddle. This gives you:
<ranzcp_user xmlns:ns1="urn:logon" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<user_id xsi:type="xsd:string">12345678</user_id>
</ranzcp_user>
But, as has been said, removing the namespace prefix entirely would result in invalid XML - no conforming processor will let you create it or read it without errors.
Could it be that the 'required' XML has this prefix declared in one of the parent elements? If not, I'd suggest it's a mistake and you should investigate this before spending time trying to remove the attribute. I suspect you'd end up undoing all that effort when the consumer works out the XML is invalid.

XDocument Error Name cannot begin with the '<' character, hexadecimal value 0x3C

I am trying to create xml file using XDcoument, but I am getting following error
Name cannot begin with the '<' character, hexadecimal value 0x3C
here is my code
XDocument d = new XDocument(
new XElement("<S:Envelope xmlns:S='http://schemas.xmlsoap.org/soap/envelope/'>",
new XElement("<S:Header xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>",
new XElement("<ns13:ACASecurityHeader xmlns='urn:us:gov:treasury:irs:ext:aca:air:7.0' xmlns:ns10='urn:us:gov:treasury:irs:msg:acauibusinessheader' xmlns:ns11='http://www.w3.org/2000/09/xmldsig#' xmlns:ns12='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:ns13='urn:us:gov:treasury:irs:msg:acasecurityheader' xmlns:ns2='urn:us:gov:treasury:irs:common' xmlns:ns3='urn:us:gov:treasury:irs:msg:form1094-1095Btransmitterupstreammessage' xmlns:ns4='urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage' xmlns:ns5='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' xmlns:ns6='urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage' xmlns:ns7='urn:us:gov:treasury:irs:msg:form1094-1095BCtransmitterreqmessage' xmlns:ns8='urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter' xmlns:ns9='urn:us:gov:treasury:irs:msg:acabusinessheader'>"),
new XElement("Author", "Moreno, Jordao")
),
new XElement("Book",
new XElement("Title", "Midieval Tools and Implements"),
new XElement("Author", "Gazit, Inbar")
)
),
new XComment("This is another comment."));
Can someone please help me on this?
here is sample XML file which I want to generate using XDocument
There is a much simpler way to do this rather than crafting the XML document by hand via XDocument, though I have an explanation and example below if you want to do it that way.
First, the simple way - create the XML as a string, and pass that string to XDocument.Parse, like this:
string xmlString = #"<S:Envelope xmlns:S=""http://schemas.xmlsoap.org/soap/envelope/""><S:Header xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""><ns13:ACASecurityHeader xmlns:ns10=""urn:us:gov:treasury:irs:msg:acauibusinessheader"" xmlns:ns11=""http://www.w3.org/2000/09/xmldsig#"" xmlns:ns12=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:ns13=""urn:us:gov:treasury:irs:msg:acasecurityheader"" xmlns:ns2=""urn:us:gov:treasury:irs:common"" xmlns:ns3=""urn:us:gov:treasury:irs:msg:form1094-1095Btransmitterupstreammessage"" xmlns:ns4=""urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage"" xmlns:ns5=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"" xmlns:ns6=""urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage"" xmlns:ns7=""urn:us:gov:treasury:irs:msg:form1094-1095BCtransmitterreqmessage"" xmlns:ns8=""urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter"" xmlns:ns9=""urn:us:gov:treasury:irs:msg:acabusinessheader""><Author>Moreno, Jordao</Author><Book><Title>Midieval Tools and Implement</Title><Author>Gazit, Inbar</Author></Book></ns13:ACASecurityHeader><!--This is another comment--></S:Header></S:Envelope>";
XDocument xDoc2 = XDocument.Parse(xmlString);
xDoc2 will contain the XML you wish to send.
If you wish to do it the long way, then there are a couple of issues with your posted code.
First, you're not correctly handling the namespaces (the xmlns: attributes). Secondly, you're including the < and > in the call to XElement, and you don't need to do that - the method takes care of those two symbols.
What you need to do is to set up the namespaces, then add them to the appropriate elements as well as creating the attributes for them.
The sample code doesn't match the posted snippet, so I worked off your sample code to show you how to go about crafting the XML by hand.
XNamespace sNS = XNamespace.Get("http://schemas.xmlsoap.org/soap/envelope/");
XNamespace wsseNS = XNamespace.Get("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XNamespace xmlnsNS = XNamespace.Get("urn:us:gov:treasury:irs:ext:aca:air:7.0");
XNamespace ns10NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:acauibusinessheader");
XNamespace ns11NS = XNamespace.Get("http://www.w3.org/2000/09/xmldsig#");
XNamespace ns12NS = XNamespace.Get("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XNamespace ns13NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:acasecurityheader");
XNamespace ns2NS = XNamespace.Get("xmlns: ns2 = 'urn:us:gov:treasury:irs:common");
XNamespace ns3NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:form1094-1095Btransmitterupstreammessage");
XNamespace ns4NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage");
XNamespace ns5NS = XNamespace.Get("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
XNamespace ns6NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage");
XNamespace ns7NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:form1094-1095BCtransmitterreqmessage");
XNamespace ns8NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter");
XNamespace ns9NS = XNamespace.Get("urn:us:gov:treasury:irs:msg:acabusinessheader");
XDocument xDoc = new XDocument(new XElement(sNS + "Envelope", new XAttribute(XNamespace.Xmlns + "S", sNS),
new XElement(sNS + "Header", new XAttribute(XNamespace.Xmlns + "wsse", wsseNS),
new XElement(ns13NS + "ACASecurityHeader", new XAttribute(XNamespace.Xmlns + "ns10", ns10NS),
new XAttribute(XNamespace.Xmlns + "ns11", ns11NS),
new XAttribute(XNamespace.Xmlns + "ns12", ns12NS),
new XAttribute(XNamespace.Xmlns + "ns13", ns13NS),
new XAttribute(XNamespace.Xmlns + "ns2", ns2NS),
new XAttribute(XNamespace.Xmlns + "ns3", ns3NS),
new XAttribute(XNamespace.Xmlns + "ns4", ns4NS),
new XAttribute(XNamespace.Xmlns + "ns5", ns5NS),
new XAttribute(XNamespace.Xmlns + "ns6", ns6NS),
new XAttribute(XNamespace.Xmlns + "ns7", ns7NS),
new XAttribute(XNamespace.Xmlns + "ns8", ns8NS),
new XAttribute(XNamespace.Xmlns + "ns9", ns9NS
new XAttribute("xmlns", xmlnsNS),
new XElement("Author", "Moreno, Jordao"),
new XElement("Book",
new XElement("Title", "Midieval Tools and Implement"),
new XElement("Author", "Gazit, Inbar"))
),
new XComment("This is another comment")
))
);
The first thing the above code does is sets up all the namespaces via XNamespace.
Next, the XML Document is constructed. The individual elements are created via XElement, with the various namespaces prefixed (i.e., new XElement(sNS + "Envelope",, and the other namespaces added via XAttribute.
Nesting can get tricky, so you have to be very careful doing it this way. The above code will produce the following XML:
<?xml version="1.0"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns13:ACASecurityHeader xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0"
xmlns:ns9="urn:us:gov:treasury:irs:msg:acabusinessheader"
xmlns:ns8="urn:us:gov:treasury:irs:msg:irsacabulkrequesttransmitter"
xmlns:ns7="urn:us:gov:treasury:irs:msg:form1094-1095BCtransmitterreqmessage"
xmlns:ns6="urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage"
xmlns:ns5="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:ns4="urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage"
xmlns:ns3="urn:us:gov:treasury:irs:msg:form1094-1095Btransmitterupstreammessage" xmlns:ns2="urn:us:gov:treasury:irs:common"
xmlns:ns13="urn:us:gov:treasury:irs:msg:acasecurityheader"
xmlns:ns12="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:ns11="http://www.w3.org/2000/09/xmldsig#"
xmlns:ns10="urn:us:gov:treasury:irs:msg:acauibusinessheader">
<Author>Moreno, Jordao</Author>
<Book>
<Title>Midieval Tools and Implement</Title>
<Author>Gazit, Inbar</Author>
</Book>
</ns13:ACASecurityHeader>
<!--This is another comment-->
</S:Header>
</S:Envelope>
What you're doing is a really hard way to do this. There is a much easier way.
You have the Xsd specifications from them, you can use the xsd command in the Visual Studio command line to generate C# objects that match the requirements automatically during serialization.
For the IRS ACA schemas, get all the XSD files into the same directory. Then in a sibling directory to the one you created, place the Common folder.
Then, in the command line navigate to the directory you created and put all the xsd files and run this command:
xsd /c IRS-EXT-ACA-AIR-7.0.xsd IRS-ACABulkRequestTransmitterMessage.xsd IRS-Form1094-1095CTransmitterUpstreamMessage.xsd IRS-CAC.xsd IRS-WSTimeStampElementMessage.xsd IRS-WSTimeStampElementMessage.xsd
You'll end up with a C# file that has almost 200 objects in it including all the enums and such necessary for generating data compliant with their specifications.

Read node value from input xml file and write it on other output xml file

I have an xml file which contains the following tag.
<ClinicalDocument xmlns:ext="http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hl7-org:v3">
Now I have to read this and write the attribute value to a string.
Right now I am using the the follwoing code.
XmlDocument xDocument = new XmlDocument();
xDocument.Load(#"c:\Test.xml");
System.Text.StringBuilder ClinicalDocument = new System.Text.StringBuilder();
ClinicalDocument.Append("<ClinicalDocument xmlns:ext=" + xDocument.SelectSingleNode("/ClinicalDocument/#xmlns:ext").Value + " xmlns:xsi=" + xDocument.SelectSingleNode("/ClinicalDocument/#xmlns:xsi").Value + " xmlns=" + xDocument.SelectSingleNode("/ClinicalDocument/#xmlns").Value + ">");
Response.Write(ClinicalDocument);
But its throwing exception "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function. "
Please suggest what am I doing wrong or is there any other alternative. I am completely new to XML.
What you're trying to get is not an ordinary attribute, it is namespace attribute. You can try using XPath namespace axis to get namespace attribute, something like this :
/*/namespace::ext
working demo example :
var xml = #"<ClinicalDocument xmlns:ext='http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:hl7-org:v3'/>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var result = doc.SelectSingleNode("/*/namespace::ext");
Console.WriteLine(result.Value);
Dotnetfiddle Demo
output :
http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0

Write NameSpaces in XML

I need to generate an XML file using C# class (XmlDocument or XDocument) with the following root element:
<ns1:ConsultaSeqRps xmlns:ns1="http://localhost:8080/WsNFe2/lote"
xmlns:tipos="http://localhost:8080/WsNFe2/tp"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ConsultaSeqRps.xsd">
I've tried various alternatives using setAttribute and XmlNamespaceManager but without success.
It's pretty straightforward, except maybe for the use of XAttribute to add a named namespace:
XNamespace ns1 = "http://localhost:8080/WsNFe2/lote";
XNamespace tipos = "http://localhost:8080/WsNFe2/tp";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
var doc = new XElement(ns1 + "ConsultaSeqRps",
new XAttribute(XNamespace.Xmlns + "ns1", ns1),
new XAttribute(XNamespace.Xmlns + "tipos", tipos),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(xsi + "schemaLocation",
"http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ConsultaSeqRps.xsd")
);
You can take the advantage of LINQ to XML, the following article will help you to Create namespace in c#
How to: Create a Document with Namespaces (C#) (LINQ to XML)
Hope that help.
Regards

Categories