I'm trying to create a SEPA XML with XmlWriter. The created XML has to look like this example:
http://www.ebics.de/fileadmin/unsecured/anlage3/anlage3_pain008/pain_ex/pain.008.003.02.xml
This is my code so far:
public void generateSepaXml()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("C:\\Users\\Sybren\\Documents\\test.xml",settings))
{
String messageId = "Message ID";
writer.WriteStartDocument();
writer.WriteStartElement("Document"); //Document start
writer.WriteAttributeString("xsi",#"schemaLocation=""urn:iso:std:iso:20022:tech:xsd:pain.008.003.02 pain.008.003.02.xsd");
writer.WriteStartElement("CstmrDrctDbtInitn"); // CstmrDrctDbtInitn tag start
writer.WriteStartElement("GrpHdr"); //GrpHeader tag start
writer.WriteStartElement("MsgId",messageId); //Message tag start
writer.WriteEndElement(); //Message tag end
writer.WriteEndElement(); //GrpHdr end
writer.WriteEndElement(); //CstmrDrctDbtInitn tag end
writer.WriteEndElement(); //Document end
writer.WriteEndDocument();
}
}
The result of my code looks like this:
How can set the text in the Document tag the same to the Document tag in my example?
And for the message tag xmlns is added when I open the xml in IE. The xmlns tag isn't visible in the result image above (in Firefox). How to remove this tag? And how can I set the text in the MsgId the same to the MsgId in the linked example xml? Maybe XMLWriter isn't the best option in my case? If so what is another better option?
Ofcourse this is only a small part of the XML but if know how it works , I think I can do the rest myself.
Just a well-meant advise (since I have some experience in the area of financial data-exchange, especially with SEPA)... I would not try to implement that shit using such a low-level XML API; there´re better ways to create complex XML documents than assembling them piece-by-piece with XmlWriter.
Since SEPA documents can become quite big, achieving it the way you´re trying will probably result in unmaintainable and error-prone spaghetti code. Instead, I would recommend to investigate into a model-driven approach (one for each SEPA use-case to implement) and then use a generator (consider using an intermediate XML format that can be transformed using XSLT) or a text-processor to produce the final output...
Related
I would like to know if there is any chance of getting specific XML node from XmlWriter.
I've got a method, which exports employees to XML document and has a structure, something like:
<header>
<agency>
...
<employees>
<employee>
....
</employee>
<empolyee>
...
</employee>
</employees>
...
in for cycle in this method each employee is created and filled with elements. The whole method for exporting this XML has already been written.
Now, at the end of the loop, I would like to create a string, which contains the node of the employee, but I don't know, how to do it with the writer which is filled with the data in the loop.
I've tried to search for some solution, but I didn't find anything good for my case. I've considered something like MemoryStream, but I think that you need to pass the stream while you are creating the XmlWriter, which in my case firstly writes the header node etc.
Could you please help me with this? I don't want to create another Writer or Reader and write the nodes twice. At first, I would like to find some better solution.
Thank you!
EDIT: I'm pasting some of the code as you want:
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = ("\t");
settings.OmitXmlDeclaration = false;
XmlWriter xmlWriter = XmlWriter.Create(filenameXml, settings);
xmlWriter.WriteStartElement("message");
xmlWriter.WriteStartElement("data");
xmlWriter.WriteStartElement("header");
xmlWriter.WriteElementString("agency", agencyNumber);
xmlWriter.WriteElementString("date", DateTime.Now.ToShortDateString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("employees");
//Loading of employees from DB and some other work
for (int i = 0; i < employeesDs.RowCount(); i++)
{
xmlWriter.WriteStartElement("employee");
//A lot of work - xmlWriter.WriteElementString so many times or WriteStartElement (address, numbers, dates etc)
xmlWriter.WriteEndElement(); // employee
//HERE I would like to add new method which stores whole Employee element created in this iteration i to the string
//After that I need to store this string to DB to VARCHAR MAX, but I don't know how to get the string of the Employee
//from the writer in this part of the code
}
//another work - closing and flushing xmlwriter, disposing etc and exporting whole xml document
I am writing a network server in C# .NET 4.0. There is a network TCP/IP connection over which I can receive complete XML elements. They arrive regularly and I need to process them immediately. Each XML element is a complete XML document in itself, so it has an opening element, several sub-nodes and a closing element. There is no single root element for the entire stream. So when I open the connection, what I get is like this:
<status>
<x>123</x>
<y>456</y>
</status>
Then some time later it continues:
<status>
<x>234</x>
<y>567</y>
</status>
And so on. I need a way to read the complete XML string until a status element is complete. I don't want to do that with plain text reading methods because I don't know in what formatting the data arrives. I can in no way wait until the entire stream is finished, as is often described elsewhere. I have tried using the XmlReader class but its documentation is weird, the methods don't work out, the first element is lost and after sending the second element, an XmlException occurs because there are two root elements.
Try this:
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var reader = XmlReader.Create(stream, settings))
{
while (!reader.EOF)
{
reader.MoveToContent();
var doc = XDocument.Load(reader.ReadSubtree());
Console.WriteLine("X={0}, Y={1}",
(int)doc.Root.Element("x"),
(int)doc.Root.Element("y"));
reader.ReadEndElement();
}
}
If you change the "conformance level" to "fragment", it might work with the XmlReader.
This is a (slightly modified) example from MSDN:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlReader reader = XmlReader.Create(streamOfXmlFragments, settings);
You could use XElement.Load which is meant more for streaming of Xml Element fragments that is new in .net 3.5 and also supports reading directly from a stream.
Have a look at System.Xml.Linq
I think that you may well still have to add some control logic so as to partition the messages you are receiving, but you may as well give it a go.
I'm not sure there's anything built-in that does that.
I'd open a string builder, fill it until I see a </status> tag, and then parse it using the ordinary XmlDocument.
Not substantially different from dtb's solution, but linqier
static IEnumerable<XDocument> GetDocs(Stream xmlStream)
{
var xmlSettings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment };
using (var xmlReader = XmlReader.Create(xmlStream, xmlSettings))
{
var xmlPathNav = new XPathDocument(xmlReader).CreateNavigator();
foreach (var selectee in xmlPathNav.Select("/*").OfType<XPathNavigator>())
yield return XDocument.Load(selectee.ReadSubtree());
}
}
I ran into a similar problem in PowerShell, but the asker's question was in C#, so I've attempted to translate it (and verified that it works). Here is where I found the clue that got me over the last little bumps (". . .The way the XPathDocument does its magic is by creating a “transparent” root node, and holding the fragments from it. I say it’s transparent because your XPath queries can use the root node axis and still get properly resolved to the fragments. . .")
The fragments of XML I'm working with happen to be smallish. If you had bigger chunks, you'd probably want to look into XStreamingElement - it can add a lot of complexity but also greatly decrease memory usage when dealing with large volumes of XML.
I have xml documents in a database field. The xml documents have no whitespace between the elements (no line feeds, no indenting).
I'd like to output them to the browser, formatted nicely. I would simply like linefeeds in there with some indenting. Is there an easy, preferably built-in way to do this?
I am using ASP.NET 3.5 and C#. This is what I have so far, which is outputting the document all in one line:
I'm about 99.9977% sure I am using the XmlWriter incorrectly. What I am accomplishing now can be done by writing directly to the response. But am I on the right track at least? :)
int id = Convert.ToInt32(Request.QueryString["id"]);
var auditLog = webController.DB.Manager.AuditLog.GetByKey(id);
var xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
xmlWriterSettings.OmitXmlDeclaration = true;
var xmlWriter = XmlWriter.Create(Response.OutputStream, xmlWriterSettings);
if (xmlWriter != null)
{
Response.Write("<pre>");
// ObjectChanges is a string property that contains an XML document
xmlWriter.WriteRaw(Server.HtmlEncode(auditLog.ObjectChanges));
xmlWriter.Flush();
Response.Write("</pre>");
}
This is the working code, based on dtb's answer:
int id = Convert.ToInt32(Request.QueryString["id"]);
var auditLog = webController.DB.Manager.AuditLog.GetByKey(id);
var xml = XDocument.Parse(auditLog.ObjectChanges, LoadOptions.None);
Response.Write("<pre>" + Server.HtmlEncode(xml.ToString(SaveOptions.None)) + "</pre>");
Thank you for helping me!
WriteRaw just writes the input unchanged to the underlying stream.
if you want to use built-in formatting, you need first to parse the XML and then convert it back to a string.
The simplest solution is possibly to use XLinq:
var xml = XDocument.Parse(auditLog.ObjectChanges);
Response.Write(Server.HtmlEncode(xml.ToString(SaveOptions.None)));
(This assumes auditLog.ObjectChanges is a string that represents well-formed XML.)
If you need more control over the formatting (indentation, line-breaks) save the XDocument to a MemoryStream-backed XmlWriter, decode the MemoryStream back to a string, and write the string HtmlEncoded.
If auditLog.ObjectChanges is the XML content that needs to be formatted, then you've stored it in an unformatted way. To format it, treat it as XML and write it to an XMLWriter to format it. Then include the formatted XML into the response, with the HTML encoding.
Its been a while since i've needed to do this so i was looking at the old school methods of writing XMLDocument from code down to a File.
In my application i am writing alot to an XMLdocument with new elements and values and periodically saving it down to disc and also reading from the file and depending on the data i am doing things.
I am using methods like File.Exists(...) _xmldoc.LoadFile(..) etc...
Im wondering probably now a days there are better methods for this with regards
Parsing the XML
Checking its format for saving down
rather then the data being saved down being treated as text but as XML
maybe what i am doing is fine but its been a while and wondered if there are other methods :)
thanks
Well there's LINQ to XML which is a really nice XML API introduced in .NET 3.5. I don't think the existing XMLDocument API has changed much, beyond some nicer ways of creating XmlReaders and XmlWriters (XmlReader.Create/XmlWriter.Create).
I'm not sure what you really mean by your second and third bullets though. What exactly are you doing in code which feels awkward?
Have you looked at the Save method of your XmlDocument? It will save whatever is in your XmlDocument as a valid formatted file.
If your program is able to use the XmlDocument class, the XmlDocument class will be able to save your file. You won't need to worry about validating before saving, and you can give it whatever file extension you want. As to your third point... an XML file is really just a text file. It won't matter how the OS sees it.
I was a big fan of XmlDocument due to its facility to use but recently I got a huge memory problem with that class so I started to use XmlReader and XmlWriter.
XmlReader can be a little bit tricky to use if your Xml file is complex because you read the Xml file sequentially. In that case, the method ReadSubTree of XmlReader can be very useful because this method returns only the xml tree under the current node so you send the new xmlreader to a function to parse the subnode content and once it is done, you continue to the next node.
XmlReader Example:
string xmlcontent = "<BigXml/>";
using(StringReader strContent = new StringReader(xmlcontent))
{
using (XmlReader reader = XmlReader.Create(strContent))
{
while (reader.Read())
{
if (reader.Name == "SomeName" && reader.NodeType == XmlNodeType.Element)
{
//Send the XmlReader created by ReadSubTree to a function to read it.
ReadSubContentOfSomeName(reader.ReadSubtree());
}
}
}
}
XmlWriter Example:
StringBuilder builder = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(builder))
{
writer.WriteStartDocument();
writer.WriteStartElement("BigXml");
writer.WriteAttributeString("someAttribute", "42");
writer.WriteString("Some Inner Text");
//Write nodes under BigXml
writer.WriteStartElement("SomeName");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
}
I want to output my InnerXml property for display in a web page. I would like to see indentation of the various tags. Is there an easy way to do this?
Here's a little class that I put together some time ago to do exactly this.
It assumes that you're working with the XML in string format.
public static class FormatXML
{
public static string FormatXMLString(string sUnformattedXML)
{
XmlDocument xd = new XmlDocument();
xd.LoadXml(sUnformattedXML);
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlTextWriter xtw = null;
try
{
xtw = new XmlTextWriter(sw);
xtw.Formatting = Formatting.Indented;
xd.WriteTo(xtw);
}
finally
{
if(xtw!=null)
xtw.Close();
}
return sb.ToString();
}
}
You should be able to do this with code formatters. You would have to html encode the xml into the page first.
Google has a nice prettifyer that is capable of visualizing XML as well as several programming languages.
Basically, put your XML into a pre tag like this:
<pre class="prettyprint">
<link href="prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="prettify.js"></script>
</pre>
Use the XML Web Server Control to display the content of an xml document on a web page.
EDIT: You should pass the entire XmlDocument to the Document property of the XML Web Server Control to display it. You don't need to use the InnerXml property.
If identation is your only cocern and if you can afford to launch xternall process, you can process xml file with HTML Tidy console tool (~100K).
The code is:
tidy --input-xml y --output-xhtml y --indent "1" $(FilePath)
Then you can display idented string on web page once you get rid of special chars.
It would be also easy to create recursive function that makes such output - simply iterate nodes starting from the root and enter next recursion step for child node, passing identation as a parameter to each new recursion call.
Check out the free Actipro CodeHighlighter for ASP.NET - it can neatly display XML and other formats.
Or are you more interested in actually formatting your XML? Then have a look at the XmlTextWriter - you can specify things like Format (indenting or not) and the indent level, and then write out your XML to e.g. a MemoryStream and read it back from there into a string for display.
Marc
Use an XmlTextWriter with the XmlWriterSettings set up so that indentation is enabled. You can use a StringWriter as "temporary storage" if you want to write the resulting string onto screen.