Extracting XML object from MIME Multipart file - c#

So I'm in a bit of a cross road here trying to consume the data in files that from my understanding (after reading up a bit) seems to be multipart soap requests (with the xml object as an attachment?).
So I've been given the task to work with xml files that look something like this:
--MIME264440613829.7322990959788848043325807015
<SOAP-ENV:Envelope>
<SOAP-ENV:Header>
...
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<eb:Manifest eb:version="2.0">
<eb:Reference xlink:href="cid:payload-1" xlink:role="aop:ROOT"/>
</eb:Manifest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--MIME264440613829.7322990959788848043325807015
Content-ID: payload-1
<?xml version="1.0" encoding="UTF-8"?>
<aop:ROOT>
...
</aop:ROOT>
--MIME264440613829.7322990959788848043325807015--
And what i need to do is to extract the XML in what seems to be the second part (or the attachment as i think people call it) from the multipart object.
My first thought was to just use some string operations with for example regex to extract the xml object, but surely there must be a better way. Also I'm currently just testing this out in a c# project.

Ok, So after contacting one of my colleagues we managed to find a solution:
So this is what we did
Using HttpMultiPartParser we could extract the xml content from the file by the code below:
using HttpMultipartParser;
using (var streamReader = new StreamReader(#"multipartFile.xml"))
{
var temp = MultipartFormDataParser.Parse(streamReader.BaseStream);
foreach (var filepart in temp.Files)
{
using (var fpSr = new StreamReader(filepart.Data))
{
var name = filepart.Name;
var contentType = filepart.ContentType;
var content = fpSr.ReadToEnd();
}
}
}

Related

C# Parsing XML in ISO-8859-1

I'm working on a tool for validating XML files grabbed from a mainframe. For reasons beyond my control every XML file is encoded in ISO 8859-1.
<?xml version="1.0" encoding="ISO 8859-1"?>
My C# application utilizes the System.XML library to parse the XML and eventually a string of a message contained within one of the child nodes.
If I manually remove the XML encoding line it works just fine. But i'd like to find a solution that doesn't require manual intervention. Are there any elegant approaches to solving this? Thanks in advance.
The exception that is thrown reads as:
System.Xml.XmlException' occurred in System.Xml.dll. System does not support 'ISO 8859-1' encoding. Line 1, position 31
My code is
XMLDocument xmlDoc = new XMLDocument();
xmlDoc.Load(//fileLocation);
As Jeroen pointed out in a comment, the encoding should be:
<?xml version="1.0" encoding="ISO-8859-1"?>
not:
<?xml version="1.0" encoding="ISO 8859-1"?>
(missing dash -).
You can use a StreamReader with an explicit encoding to read the file anyway:
using (var reader = new StreamReader("//fileLocation", Encoding.GetEncoding("ISO-8859-1")))
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
// ...
}
(from answer by competent_tech in other thread I linked in an earlier comment).
If you do not want the using statement, I guess you can do:
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(File.ReadAllText("//fileLocation", Encoding.GetEncoding("ISO-8859-1")));
Instead of XmlDocument, you can use the XDocument class in the namespace System.Xml.Linq if you refer the assembly System.Xml.Linq.dll (since .NET 3.5). It has static methods like Load(Stream) and Parse(string) which you can use as above.

Xdocument, Xelement.Save incorrect encoding

I 'm having problem with the code presented:
string serializedLicence = SerializationHelper.ToXML(licenceInfo);
var licenceFileXml = new XElement("Licence", new XElement("LicenceData", serializedLicence)));
XmlDocument signedLicence = SignXml(licenceFileXml.ToString(), Properties.Resources.PRIVATE_KEY);
signedLicence.Save(saveFileDialogXmlLicence.FileName);
The created file has an incorrect coding of strings send to XElement constructors aswell as the signature, that assigned with custom SignXml() method (which creates signature with XmlDocument.DocumentElement.AppendChild() method, but that's irrelevant right now). The output:
<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<Licence>
<LicenceData><?xml version="1.0" encoding="utf-16"?>
<LicenceInfo
//stuff stuff stuff
</LicenceInfo></LicenceData>
<Signature><SignedInfo xmlns="h stuff stuff stuff</Signature>
</Licence>
So basically I'm taking serialized object string and put it between markers, and this part gets encoded wrong. Debugger shows me, that the text in XElement object is holding < and > just after creating it. I could parse it manually, but that's inapropriate.
Note: befeore that, I was straight signing the deserialisation xml and it worked fine, so I can't figure it out why XDocument uses different encoding than XmlSerializer/XmlDocument object.
Also: I think I could just use XmlDocument object to build the file, but I'm curious what's wrong.
You're adding serializedLicence as string, so it's treated as text, not as XML and that's why it looks like that in you document.
var licenceFileXml = new XElement("Licence",
new XElement("LicenceData",
XDocument.Parse(serializedLicence).Root)));

Convert Encoded XML Tags To Nodes

I have the following XML obtain via a SOAP call.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetValueListForFieldResponse xmlns="http://URLHere/webservices/">
<GetValueListForFieldResult>
&lt;SelectDef&gt; &lt;Id&gt;1736&lt;/Id&gt; &lt;SelectName&gt;Values List&lt;/SelectName&gt; &lt;GlobalFlag&gt;False&lt;/GlobalFlag&gt; &lt;Sort&gt;1&lt;/Sort&gt; &lt;SelectDefValues&gt; &lt;SelectDefValue&gt; &lt;guid&gt;aaf6f3a7-6a74-4187-b4e7-3a9355b16796&lt;/guid&gt; &lt;Id&gt;14692&lt;/Id&gt; &lt;Name&gt;Open&lt;/Name&gt; &lt;Description&gt;&lt;/Description&gt; &lt;Color&gt;#000000&lt;/Color&gt; &lt;DefaultFlag&gt;False&lt;/DefaultFlag&gt; &lt;SortOrder&gt;1&lt;/SortOrder&gt; &lt;select_id&gt;1736&lt;/select_id&gt; &lt;/SelectDefValue&gt; &lt;SelectDefValue&gt; &lt;guid&gt;f5082b54-d799-4fdc-80c1-0e232b360057&lt;/guid&gt; &lt;Id&gt;14693&lt;/Id&gt; &lt;Name&gt;Closed&lt;/Name&gt; &lt;Description&gt;&lt;/Description&gt; &lt;Color&gt;#000000&lt;/Color&gt; &lt;DefaultFlag&gt;False&lt;/DefaultFlag&gt; &lt;SortOrder&gt;0&lt;/SortOrder&gt; &lt;select_id&gt;1736&lt;/select_id&gt; &lt;/SelectDefValue&gt; &lt;SelectDefValue&gt; &lt;guid&gt;94e29e78-2ab3-463f-bbb6-ab7f36003c7f&lt;/guid&gt; &lt;Id&gt;14780&lt;/Id&gt; &lt;Name&gt;Past Due&lt;/Name&gt; &lt;Description&gt;&lt;/Description&gt; &lt;Color&gt;#000000&lt;/Color&gt; &lt;DefaultFlag&gt;False&lt;/DefaultFlag&gt; &lt;SortOrder&gt;2&lt;/SortOrder&gt; &lt;select_id&gt;1736&lt;/select_id&gt; &lt;/SelectDefValue&gt; &lt;/SelectDefValues&gt; &lt;/SelectDef&gt;
</GetValueListForFieldResult>
</GetValueListForFieldResponse>
</soap:Body>
Is there a way to convert the data in the GetValueForFieldResult node to actual XML so I can parse the data?
Below is how I'm making the SOAP call and storing the XML. I'm learning C# and if below is a complete mess my appologies.
HttpWebRequest reqVl = (HttpWebRequest)WebRequest.Create(serverURL + "/ws/Field.asmx");
reqVl.Headers.Add("SOAPAction", "http://URL/webservices/GetValueListForField");
reqVl.ContentType = "text/xml;charset=\"utf-8\"";
reqVl.Accept = "text/xml";
reqVl.Method = "POST";
using (Stream stm = reqVl.GetRequestStream())
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(VLsoap);
}
}
WebResponse responseVL = reqVl.GetResponse();
Stream responseStreamVL = responseVL.GetResponseStream();
XmlReader rdrVL = XmlReader.Create(responseStreamVL);
XmlDocument vls = new XmlDocument();
vls.Load(rdrVL);
Here is some code to achieve what you want - however, please read the text afterwards for an explanation of why this may not be the best way to get what you want.
Tested as working with your message and .Net 4.
Assuming vls contains your SOAP message as XML, we split the problem into two halves; parsing the soap message, and extracting and decoding the contents of the GetValueListForFieldResult node into a string that can be loaded into another XmlDocument
Part I - getting the contents of the GetValueListForFieldResult node
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(vls.NameTable);
namespaceManager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
namespaceManager.AddNamespace("default", "http://URLHere/webservices/");
XmlNode payLoadNode =
vls.SelectSingleNode("/soap:Envelope/soap:Body/default:GetValueListForFieldResponse/default:GetValueListForFieldResult", namespaceManager);
string encodedXml = payLoadNode.InnerText;
Part II - getting the encoded string into an Xml Document
It is at this point that we have the encoded string. We have a couple of choices for decoding this HTML; as I'm using .Net 4 I've gone for the simplest:
string decodedXml = WebUtility.HtmlDecode(encodedXml);
XmlDocument payloadDocument = new XmlDocument();
payloadDocument.LoadXml(decodedXml);
If you are using .Net 3.5 then you'll have to consider adding a reference to System.Web and using HttpUtility.HtmlDecode instead to decode the string.
Parsing your message above gives me the result:
<SelectDef>
<Id>1736</Id>
<SelectName>Values List</SelectName>
<GlobalFlag>False</GlobalFlag>
<Sort>1</Sort>
<SelectDefValues>
<SelectDefValue>
<guid>aaf6f3a7-6a74-4187-b4e7-3a9355b16796</guid>
<Id>14692</Id>
<Name>Open</Name>
<Description></Description>
<Color>#000000</Color>
<DefaultFlag>False</DefaultFlag>
<SortOrder>1</SortOrder>
<select_id>1736</select_id>
</SelectDefValue>
<SelectDefValue>
<guid>f5082b54-d799-4fdc-80c1-0e232b360057</guid>
<Id>14693</Id>
<Name>Closed</Name>
<Description></Description>
<Color>#000000</Color>
<DefaultFlag>False</DefaultFlag>
<SortOrder>0</SortOrder>
<select_id>1736</select_id>
</SelectDefValue>
<SelectDefValue>
<guid>94e29e78-2ab3-463f-bbb6-ab7f36003c7f</guid>
<Id>14780</Id>
<Name>Past Due</Name>
<Description></Description>
<Color>#000000</Color>
<DefaultFlag>False</DefaultFlag>
<SortOrder>2</SortOrder>
<select_id>1736</select_id>
</SelectDefValue>
</SelectDefValues>
</SelectDef>
The Alternative
The reason you may not wish to do it this way is because the response you are receiving has been wrapped using SOAP; you may therefore wish to try and consume the service you are connecting to as a web service and generate a proxy library; this will encapsulate all of the code you see above, as well as the code you have written, in a proxy that may allow you to retrieve the values you want in a more type safe and less fragile manner. Support for this is built into .Net.
Further, as the URL you are connecting to terminates in ASMX, it tells you that this is most likely a native .Net web service so wiring your client up to it should be simple.
The MSDN topic "How to add a Reference to a Web Service" should help you in generating the proxy and avoiding all of the code above.

XML header missing after converting an XML file into a Binary Format File

I have a problem. I have an XML spreadsheet file that I'm trying to send via email. So I converted into a binary file and attached it to an email. The problem is when I'm trying to open it (on Excel), it's not showing the data that I saved. When I opened it like an XML file I realized that it didn't saved the XML header:
The way it should be:
<?xml version="1.0" encoding="utf-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
...
<Styles>
...
</Styles>
<Worksheet>
...
</Worksheet></Workbook>
after converting:
<Worksheet>
...
</Worksheet>
I've tried to use an xmldocument but i wasn't working, I also tried using a string, still not working. This is how I convert the XML to binary:
UTF8Encoding encoding = new UTF8Encoding();
binaryFile = encoding.GetBytes(xmlFile);
How can I fix this problem?
Thanks.
I think we need more information on how you're converting the XML file.
From your description it sounds like you've saved an Excel Spreadsheet to XML and for whatever reason you cannot just attach this text document to an email. My guess is you're using a method to attach the XML file that requires a byte array and can't just be provided a file location. If you could provide more information on this, it would help us figure out where things are going wrong for you.
The part I'm really stuck on is:
I've tried to use an xmldocument but i wasn't working, I also tried
using a string, still not working.
How did you try string? Did you read the file from disk using FileStream? If so, you should have been able to retrieve the full contents of the file.
Were you using XmlDocument the whole time and trying XmlDocument.OuterXml? This probably won't give you the control headers since they're not part of the XML body inside the root node.
So really there are two things I would have tried. First, if I had an XML file on disk and needed to attach it to an email through code and my only option was to provide a byte array, I'd do something like:
using (FileStream fs = new FileStream("", FileMode.Open, FileAccess.Read))
{
byte[] binaryFile = new byte[fs.Length];
fs.Read(binaryFile, 0, buff.LongLength);
//Copy the byte array to your email object.
}
Now if this isn't what you're doing, you'll need to provide a lot more detail on what you are starting with (file on disk?), what you need to do (send automated email?), what constraints you have and any other information that would limit potential solutions.
I've found my mistake: I didn't serialized the XML file so that's why after the conversion it just shows the data without the XML header. so there's 2 ways to resolve this problem:
first, we can concatenate the header with the data string, or we can use the serialize function. This is where I've found how to do it.

How to generate XML on MonoTouch?

I need to generate XML on MonoTouch application ? How i can create like this,
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
...
</root>
I need to post the XML to web service as string format. And again I want to parse the response data. Response data also XML format string. I done it in j2me applications. But I don't know how to do this on MonoTouch? Anyone tell me How to do this?
My favorite API these days is the System.Xml.Linq API, look at the documentation and samples here:
http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.aspx
For what you want, this is very easy:
var s = new XDocument () {
new XElement ("root")
};
Console.WriteLine ("The XML is: {0}", s.ToString ());
You can create the XML by using the XmlWriter class.
The easiest way to parse XML would be to use LINQ.

Categories

Resources