Append XMLDocument to other - c#

I have following two xml strings
<?xml version="1.0"?>
<AccessRequest xml:lang='en-US'>
<AccessLicenseNumber>YOURACCESSLICENSENUMBER</AccessLicenseNumber>
<UserId>YOURUSERID</UserId>
<Password>YOURPASSWORD</Password>
</AccessRequest>
and
<?xml version="1.0" ?>
<RatingServiceSelectionRequest>
<PickupType>
<Code>01</Code>
</PickupType>
<Shipment>
<Description>Rate </Description>
<Shipper>
<Address>
<PostalCode>originzip</PostalCode>
</Address>
</Shipper>
<ShipTo>
<Address>
<PostalCode>destinationzip</PostalCode>
<CountryCode>countrycode</CountryCode>
</Address>
</ShipTo>
<Service>
<Code>11</Code>
</Service>
<Package>
<PackagingType>
<Code>02</Code>
<Description>Package</Description>
</PackagingType>
<Description>Rate Shopping</Description>
<PackageWeight>
<Weight>weight</Weight>
</PackageWeight>
</Package>
<ShipmentServiceOptions/>
</Shipment>
</RatingServiceSelectionRequest>
I want to append second xml string to first one. I tried writing both XmlDocuments to a XmlWriter. But it throws exception "Cannot write XML declaration. XML declaration can be only at the beginning of the document."
Stream stm = req.GetRequestStream();
XmlDocument doc1 = new XmlDocument();
XmlDocument doc2 = new XmlDocument();
doc1.LoadXml(xmlData1);
doc2.LoadXml(xmlData2);
XmlWriterSettings xws = new XmlWriterSettings();
xws.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlWriter xw = XmlWriter.Create(stm, xws))
{
doc1.WriteTo(xw);
doc2.WriteTo(xw);
}
How can I append it as is? Please help

Remove <?xml version="1.0" ?> from second xml string before appending it to first xml string.

I had this problem in the past. The two lines of code below did the job:
var MyDoc = XDocument.Load("File1.xml");
MyDoc.Root.Add(XDocument.Load("File2.xml").Root.Elements());
If you already have strings ready, then please use the Parse function instead of Load.
Please notice I am using the System.Xml.Linq that uses XDocument instead of XmlDocument class.
EDIT
As I understood, you need both documents to be concatenated as is. The problem is that it will eventually leads to an invalid XML document for two reasons :
the document will contain two root nodes: AccessRequest and RatingServiceSelectionRequest. A valid XML document contains only one root node.
There must be only one <?xml version="1.0" ?> XML declaration at the beginning of a document.
If the UPS api your are using is fed with an invalid XML, you unfortunately can not use XML objects. Therefore you will have to use a simple string concatenation to achieve what you want:
var xml = xmlData1 + xmlData2;

Related

XmlDocument, preformatted xml: Add new line after XML declaration only

I need to add a line after xml declaration to process a file on an external system that rejects it if missing.
I had formatted the doc by myself on creation and signing it, so I don't want to mess with formatting as corrupts the signature (it has also third-party external signed documents)
.
Yes, I can open it as text, use replace "?><" by "?>\r\n<", save it, or do everything manually, but I want to do it "the XmlDocument" way.
What I have:
<?xml version="1.0" encoding="ISO-8859-1"?><LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
What I need:
<?xml version="1.0" encoding="ISO-8859-1"?>
<LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
Relevant code:
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
var dec = xmlDoc.CreateXmlDeclaration("1.0", Constantes.SaveEncoding.EncodingName,"no");
using (var sw = new StreamWriter(salida, false, Constantes.SaveEncoding))
{
xmlDoc.Save(sw);
}
Note I am not using indentations and PreserveWhitespace has not worked fine for me.
Any suggestions or best way to do it?

How to add data after xml in c# and read the xml after?

I've got to create a file with xml header and after that i have to put normal data, smthing like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
Data of the file....
I've already got the code to write it to the file.
Code for that part:
private void setHeader(FileStream output, string nod2, string nod3, string )
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
doc.AppendChild(docNode);
XmlNode header = doc.CreateElement("Header");
doc.AppendChild(header);
XmlNode algorithm = doc.CreateElement("Algorithm");
algorithm.InnerText = "alg";
header.AppendChild(algorithm);
XmlNode node2= doc.CreateElement("nod2");
node2.InnerText = nod2;
header.AppendChild(node2);
XmlNode node3= doc.CreateElement("nod3");
node3.InnerText = nod3;
header.AppendChild(node3);
XmlNode node= doc.CreateElement("node");
header.AppendChild(node);
XmlNode user1 = doc.CreateElement("User");
node.AppendChild(user1);
XmlNode mail = doc.CreateElement("Email");
user1.AppendChild(mail);
XmlNode sessionKey = doc.CreateElement("SessionKey");
user1.AppendChild(sessionKey);
doc.Save(output);
}
It work's pretty well, but when i want to read it with
private void readHeader(FileStream input, out string algorithm)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
}
I got an error that when the "Data of the file..." starts: "Data on the root level is invalid".
Is there a way to do it with the data after whole xml, or have i to add the data as a node?
This can be done in multiple ways. In comments, you've indicated that the best way is unacceptable for reasons outside the scope of the discussion. For completeness, I'm going to put that one first anyway. Skip down to tl;dr for what I think you'll have to end up doing.
The preferred way to do this is to base64 encode the encrypted data and put it in a CDATA block:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<File>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
<Data><![CDATA[
ICAgIFhtbE5vZGUgYWxnb3JpdGhtID0gZG9jLkNyZWF0ZUVsZW1lbnQoIkFsZ29yaXRobSIpOw0K
ICAgIGFsZ29yaXRobS5Jbm5lclRleHQgPSAiYWxnIjsNCiAgICBoZWFkZXIuQXBwZW5kQ2hpbGQo
YWxnb3JpdGhtKTsNCiAgICBYbWxOb2RlIG5vZGUyPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMiIp
Ow0KICAgIG5vZGUyLklubmVyVGV4dCA9IG5vZDI7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5v
ZGUyKTsNCiAgICBYbWxOb2RlIG5vZGUzPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMyIpOw0KICAg
IG5vZGUzLklubmVyVGV4dCA9IG5vZDM7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5vZGUzKTs=
]]></Data>
</File>
That's the canonical answer to this question.
But you've told me that in your case, a requirement has been imposed that you can't do it that way.
Second choice is MIME (actually, MIME might be the first choice and the above might be the second). But I have a feeling they won't like MIME either.
Third choice, read the file as a string and search for some marker that's inserted between the XML and the binary data, something like a MIME boundary.
tl;dr
If they won't let you add such a marker to the file (and I bet they won't), search for the first occurrence of the substring "</Header>":
var xml = File.ReadAllText(filePath);
var endTag = "</Header>";
var headerXML = xml.Substring(0, xml.IndexOf(endTag) + endTag.Length);
var xdHeader = new XmlDocument();
xdHeader.LoadXml(headerXML);
I tested your code with writing directly to a file, doc.Save(#"c:\temp\test1.xml");
And loading from that file works fine. So there is nothing wrong with your xml document. Check your FileStream. Do you flush and close it properly? Does it have UTF-8 encoding?
What's the input in the node strings. Nothing that is invalid according to xml rules?
After a single root node, only comments and processor instructions can be written to xml. So, you can try to write your data in the comments.
It will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
...
</Header>
<!-- your data -->
<!-- another data -->
This method has limitations: your data may not contain -- (double-hyphen) and may not end in -.
But it is better, of course, not to do so.

Read XML with Arabic data embedded c#

I am trying to load an XML file that contains a mix of ASCII text and Arabic characters. Here is the top snippet:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ar_EG">
<context>
<message>
<location filename="ui/aboutdialog.cpp" line="90"/>
<source>You have </source>
<translation type="unfinished">يوجد لديك</translation>
</message>
<message>
<location filename="ui/aboutdialog.cpp" line="90"/>
<source> launches left</source>
<translation type="unfinished">عدد التشغيلات المتبقية</translation>
</message>
</context>
I want to load this up into a C# TreeView object, but I am having issues with loading into XDocument or XMLDocument.
Using this:
XDocument xd = XDocument.Load(File.ReadAllText(tbxTSFileName.Text));
or
XDocument xd = XDocument.Load(File.ReadAllText(tbxTSFileName.Text, Encoding.GetEncoding(874)));
Gives me a "Invalid URI: Uri string is too long" error.
Using this:
XmlDocument xd = new XmlDocument();
xd.Load(tbxTSFileName.Text);
Gives the error "Invalid character in the given encoding. Line 9 position 40".
Read the documentation for the method you're calling.
XDocument.Load takes a URL, not an XML string.
You want XDocument.Parse.
Your reader needs to use utf-8, as indicated in the document itself. Ideally, you would use an XML reader and it would take care of using the indicated encoding itself.

Why XDocument can't get element out of this wellform XML text?

I'm trying to get the value of the Address element from the following XML text, but it's not finding it unless I remove xmlns="http://www.foo.com" from the Root element. However, the XML is valid even with it. What's the problem here?
Since I'm getting the XML text from a web service, I don't have control over it, but I can strip out the xmlns part if I have to as the last resort.
<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.foo.com">
<Address>Main St SW</Address>
</Root>
var doc = XDocument.Parse(xmlTextAbove);
var address = doc.Descendants().Where(o => o.Name == "Address").FirstOrDefault();
Console.WriteLine(address.Value); // <-- error, address is null.
As your xml contains a namespace, you have to mention that in code. This will work:
XNamespace nsSys = "http://www.foo.com";
XElement xDoc = XElement.Load("1.xml");
XElement xEl2 = xDoc.Descendants(nsSys + "Address").FirstOrDefault();
However I had to change your xml a little bit, as it contained repeated xmlns:xsi and xmlns:xsd which should occur only once per xml format:
<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.foo.com" >
<Address>Main St SW</Address>
</Root>
Related article in MSDN: XNamespace Class
The document root's XML namespace is included in the textual representation of o.Name, which is actually an instance of XName so the condition never matches.
The easiest fix is to use LocalName for the comparison:
.Where(o => o.Name.LocalName == "Address")

How to add xmlnamespace to a xmldocument

Im trying to create a xml the should look like this
<?xml version="1.0" encoding="iso-8859-1"?>
<MyTestSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Tests>
<Test>
<messaure>1</messaure>
<height>4</height>
</Test>
<Test>
<messaure>4</messaure>
<height>53</height>
</Test>
</Tests>
</MyTestSet>
Its not a problem to create the Tests or Test elements, but what is the best way to Create the "MyTestSet" including the namespaces?
Im using c# XMLDocument
This works for me:
XmlDocument.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlDocument.DocumentElement.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
If you want to create the entire document you've posted, you might not want to forget the XML declaration:
XmlDeclaration xml_declaration;
xml_declaration = XmlDocument.CreateXmlDeclaration("1.0", "ISO-8859-1", "yes");
XmlElement document_element = XmlDocument.DocumentElement;
XmlDocument.InsertBefore(xml_declaration, document_element);
In certain cases you might need it.
This question also shows another way of doing this:
Creating a specific XML document using namespaces in C#
You could alternatively use the XmlNamespaceManager class
http://msdn.microsoft.com/en-us/library/d6730bwt%28VS.80%29.aspx
Finally there is always Linq too, you could use a XDocument and XNamespace
http://msdn.microsoft.com/en-us/library/bb387075.aspx
XmlDocument xmlDocSPack = new XmlDocument();
XmlNode xmldocNode = xmlDocSPack.CreateXmlDeclaration("1.0", "", null);
xmlDocSPack.AppendChild(xmldocNode);
XmlElement LiftsMainNode = xmlDocSPack.CreateElement("Lifts");
LiftsMainNode.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
xmlDocSPack.AppendChild(LiftsMainNode);
xmlDocSPack.Save("SPack"+DateTime.Now.Year + ".xml");
Output :
<?xml version="1.0"?>
<Lifts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />

Categories

Resources