Getting specific XML Node from XmlWriter C# - c#

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

Related

Find and append to file without loading it in memory?

Im writing a simple XML file for logging that looks like this :
<root>
<objects>
</objects>
</root>
The file is created the first time like this
using (xmlWriter = new XmlTextWriter(filePathAndName, System.Text.Encoding.UTF8))
{
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("root");
xmlWriter.WriteStartElement("objects");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
}
Now I need to place objects(serialized data contracts in string format) within the objects tag without loading it to memory.
I have found a lot of suggestions on how to do this but all loads the entire file into memory and thats no good when the files is large.
My thought is this :
Open file with some kind of reader
Search from end of file to </objects> tag
Store the index and close the reader/file
Open the file again but this time as a writer
Write the serlized datacontract to the index(just before the
Close file
I'm however not sure how to do this properly in C#?
The solution for me in this case was XML Inclusion Technique, it is not perfect but the login is much simplier. I can use appendToFile instead of manipulate or read into memory.

XmlWriter create SEPA XML

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...

C# Reproducing RSS feed

I have made a program that scans rss feeds. This same program creates feeds from elements it has crawled. This means that the rss feeds are not identical, but the items must be. It copies it. It is therefore essential that what comes out is the same thing that comes in.
Now, there are occurences where elmenents in the input rss's has elements with names like this:
<dc:creator>tomatoes</dc:creator>
Now, when i scan this it works perfectly. The element get saved to database and everything is jolly good.
When i try to write it out again to an RSS feed, using these codelines (and a bunch of foreaches, if's +++)
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " ";
settings.NewLineOnAttributes = true;
XmlWriter feedWriter = XmlWriter.Create(sb, settings);
And this line for each element:
feedWriter.WriteElementString(keyAndValue[0], keyAndValue[1]);
I get this error message if i hit the example element above:
Invalid name character in 'dc:creator'. The ':' character, hexadecimal value 0x3A, cannot be included in a name.
Now, i have found a lot of articles where this error has been mentioned. And in almost all of them they questioneer is told that this is not correct XML, and should drop writing the ':'. I however can't.
I found one example where you could use another overloaded method of XmlWriter, this one:
feedWriter.WriteElementString(prefixAndKey[0],prefixAndKey[1],"Namespace",keyAndValue[1]);
However this causes the element to look like this:
<dc:creator xmlns:something="NameSpace">tomatoes</dc:creator>
This is, as you all know not the same as the one above because it contains the xmlns bit.
I also tried another 'hack' which would work as follows:
StringBuilder sb = new StringBuilder();
StringWriter stringWriter = new StringWriter(sb);
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
and
feedWriter.WriteElementString(keyAndValue[0], keyAndValue[1]);
This built and did not return errors, but when i opend it in Firefox, it displayed 0 items.
I then took a closer look at the feed i was getting this elements from, and it contained a rss element like this:
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
I am currently trying to replicate this.
Is there a reason why this might work? why?
Is there an easier way to do this?
Do i have to add a xmlns:dc or xmlns:itunes or whatever tag for all the different kinds of tags there is out there?
I need a simple and secure way of dealing with this, no matter what comes in the input rss feeds.
A quick snippet with XDocument:
XNamespace dc = #"http://purl.org/dc/elements/1.1/";
XElement doc = new XElement("items",
new XAttribute(XNamespace.Xmlns + "dc", dc),
new XElement("item",
new XElement("title", "test"),
new XElement(dc + "creator", "tomatoes"))) ;
Gives
<items xmlns:dc="http://purl.org/dc/elements/1.1/">
<item>
<title>test</title>
<dc:creator>tomatoes</dc:creator>
</item>
</items>

How to read, store and delete xml data in C#

<SMSWall run="yes" nonstop="False">
<starttime>10:15:25 PM</starttime>
<endtime>10:15:25 PM</endtime>
</SMSWall>
<MediaPlayer run="yes" nonstop="False">
<starttime>10:15:25 PM</starttime>
<endtime>10:15:25 PM</endtime>
</MediaPlayer>
<Bidding run="yes" nonstop="False">
<starttime>10:15:25 PM</starttime>
<endtime>10:15:25 PM</endtime>
</Bidding>
This is my xml file. Now I want to read the xml, store the value in a variable (and also want the data to read from the string), and leave the .xml file so that it can be deleted.I also want to read the value node wise like:
XmlDocument document = new XmlDocument();
document.Load("Schedule.xml");
XmlNode ht=document.SelectSingleNode("SMSWall/#run");
Your current XML file is not in correct format (i.e save it as .xml and open it with IE, you will give an error). So you should add <root> ... </root> (or other name).
In all I think best way to treat with XML is using System.Xml.Linq library, like XDocument and XElement :
Loading data: XDocument.Load(filename);
Creating item: XElement root = new XElement("Root");
Searching: document.Descendants("Root"), ...
See MSDN for other samples.
I prefer to create a DataSet and then use it like this:
DataSet1 ds = new DataSet1();
ds.ReadXml("test.xml", XmlReadMode.ReadSchema);
//do something
ds.WriteXml("test.xml", XmlReadMode.ReadSchema);
A typed DataSet will provide you typed tables and rows. You can get rows by index or query. You can find more about the here.

xml and files on disc interaction

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();
}

Categories