I'm trying to read a dataset as xml and load it into an XML Document.
XmlDocument contractHistoryXMLSchemaDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
//XmlWriterSettings xmlWSettings = new XmlWriterSettings();
//xmlWSettings.ConformanceLevel = ConformanceLevel.Auto;
using (XmlWriter xmlW = XmlWriter.Create(ms))
{
xmlW.WriteStartDocument();
dsContract.WriteXmlSchema(xmlW);
xmlW.WriteEndDocument();
xmlW.Close();
using (XmlReader xmlR = XmlReader.Create(ms))
{
contractHistoryXMLSchemaDoc.Load(xmlR);
}
}
}
But I'm getting the error - "Root Element Missing".
Any ideas?
Update
When i do xmlR.ReadInnerXML() it is empty. Does anyone know why?
NLV
A few things about the original code:
You don't need to call the write start and end document methods: DataSet.WriteXmlSchema produces a complete, well-formed xsd.
After writing the schema, the stream is positioned at its end, so there's nothing for the XmlReader to read when you call XmlDocument.Load.
So the main thing is that you need to reset the position of the MemoryStream using Seek. You can also simplify the whole method quite a bit: you don't need the XmlReader or writer. The following works for me:
XmlDocument xd = new XmlDocument();
using(MemoryStream ms = new MemoryStream())
{
dsContract.WriteXmlSchema(ms);
// Reset the position to the start of the stream
ms.Seek(0, SeekOrigin.Begin);
xd.Load(ms);
}
XmlDocument contractHistoryXMLSchemaDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
dsContract.WriteXml(ms);
ms.Seek(0, SeekOrigin.Begin);
using(XmlReader xmlR = XmlReader.Create(ms))
{
contractHistoryXMLSchemaDoc.Load(xmlR);
}
}
All you really need to do is to call contractHistoryXMLSchemaDoc.Save(ms). That will put the xml into the MemoryStream.
XmlDocument contractHistoryXMLSchemaDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
contractHistoryXMLSchemaDoc.Save(ms);
ms.Flush();
}
Here you go.
If from the naming convention of your variables, (not though the question you asked, which appears to change...), you need to load the XML scema of the data set into the XML document that you named with schema, below is the code to load schema of the dataset into an XMLDocument.
I want the schema of the dataset in a separate XML document. – NLV Apr 19 '10 at 12:01
Answer:
XmlDocument contractHistoryXMLSchemaDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
dsContract.WriteXmlSchema(ms);
ms.Seek(0, SeekOrigin.Begin);
contractHistoryXMLSchemaDoc.Load(ms);
}
If you are looking for how to load the dataset table data into an XML document (note I removed the word Schema from the XMLDocument variable name)
Your Question:
Sorry, i dont get you. I need to get the xml of that dataset into an xml document. – NLV Apr 19 '10 at 11:56
Answer:
XmlDocument contractHistoryXMLDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
dsContract.WriteXml(ms,XmlWriteMode.IgnoreSchema);
ms.Seek(0, SeekOrigin.Begin);
contractHistoryXMLDoc.Load(ms);
}
If you want the Schema and data set in separate documents, the code is above.
If you want just the schema or just the data in and xml document, use the above bit of code that pertains to your question.
If you want both the XML Schema and the Data in the same XMLDocument, then use this code.
XmlDocument contractHistoryXMLDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
dsContract.WriteXml(ms,XmlWriteMode.WriteSchema);
ms.Seek(0, SeekOrigin.Begin);
contractHistoryXMLDoc.Load(ms);
}
Your Question:
But I'm getting the error - "Root Element Missing".
Any ideas?
Update
When i do xmlR.ReadInnerXML() it is empty. Does anyone know why?
NLV
Answer:
There are underlying issues in your code in the way you think it is working, which means it is not really creating the XMLSchema and XmlData (dsContract), which is why you are seeing a blank XMLDocument.
It would probably help you to fully explain what you wish, and then not reply to everyone using partial sentences of which are misunderstood and your having to keep replying with more partial sentences.
Related
I have to modify a incoming SOAP XML message to add a namespace to one of the elements so that the deserialisation will work. However when I add the xmlns attribute to the correct element, I get an error when I try to load the xml in to an XmlWriter via a stream (which I need to do to in my IClientMessageInspector implementation to replace the Message reply).
The prefix '' cannot be redefined from '' to 'http://www.example.com' within the same start element tag.
I have a work around, which is that after I've modifed the attribute, I reload the entire XML document from it's own OuterXML. This works for some reason, but makes me think there must be a 'correct' way to do this.
Here's a sample test that demonstrates the problem and my current solutions:
[Test]
public void XmlNamespaceTest()
{
var originalXmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><TestElement><Child>thing</Child></TestElement>";
var desiredXmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><TestElement xmlns=\"http://www.example.com\"><Child>thing</Child></TestElement>";
var doc = new XmlDocument();
doc.LoadXml(originalXmlString);
Assert.That(originalXmlString, Is.EqualTo(doc.OuterXml));
// Write this document via an XMLWriter
var ms = new MemoryStream();
var xmlWriter = XmlWriter.Create(ms);
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
ms.Position = 0;
StreamReader sr = new StreamReader(ms);
var originalXmlViaXmlWriter = sr.ReadToEnd();
Assert.That(originalXmlString, Is.EqualTo(originalXmlViaXmlWriter));
// Add the namespace to the element
((XmlElement)doc.GetElementsByTagName("TestElement").Item(0))?.SetAttribute("xmlns", "http://www.example.com");
Assert.That(desiredXmlString, Is.EqualTo(doc.OuterXml));
// Now attempt to write this modified xml via an XMLWriter
ms.SetLength(0);
xmlWriter = XmlWriter.Create(ms);
//Uncomment line below to fix the error.
//doc.LoadXml(doc.OuterXml);
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
ms.Position = 0;
sr = new StreamReader(ms);
var modifedXmlViaXmlWriter = sr.ReadToEnd();
Assert.That(desiredXmlString, Is.EqualTo(modifedXmlViaXmlWriter));
}
According to this you can't change an elements namespace in an XmlDocument. This is also what #LocEngineer found in his comment. The referenced article mentions that the only way to do this is to save and reload the XmlDocument, which is exactly what you are doing.
If you are in a position to use XDoxument instead, it is possible. See this answer for a solution.
I have an Xdocument object which is populated with xml (the definition for a report -rdl). I would like to give the contents of this XDocument to the report viewer.
this.reportViewer1.LocalReport.LoadReportDefinition();
LoadReportDefinition only seems to take either TextReader or FileStream arguments....but my report definition is loaded within my XDocument? How can I stream the contents of my XDocument?
You can use the StringReader class like so:
using (var textReader = new StringReader(xDocument.ToString()))
{
this.reportViewer1.LocalReport.LoadReportDefinition(textReader);
}
Or alternatively use a Stream:
using (var stream = new MemoryStream())
{
xDocument.Save(stream);
stream.Position = 0;
this.reportViewer1.LocalReport.LoadReportDefinition(stream);
}
The code below is causing the " Data at the root level is invalid. Line 1, position 1. "
I like to keep the code indent(linebreak) but keep having the problem as mentioned above. I could use the TextReader to load the xml but it will remove the indent which i don't like it. If you know how to fix problem please let me know. Thanks
public XmlDocument MYXML()
{
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = false;
wSettings.OmitXmlDeclaration = false;
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms, wSettings);// Write Declaration
xw.WriteStartDocument();
// Write the root node
xw.WriteStartElement("Library");
// Write the books and the book elements
xw.WriteStartElement("Book");
xw.WriteStartAttribute("BookType");
xw.WriteString("Hardback");
xw.WriteEndAttribute();
xw.WriteStartElement("Title");
xw.WriteString("Door Number Three");
xw.WriteEndElement();
xw.WriteStartElement("Author");
xw.WriteString("O'Leary, Patrick");
xw.WriteEndElement();
xw.WriteEndElement();
xw.WriteEndElement();
// Close the document
xw.WriteEndDocument();
// Flush the write
xw.Flush();
Byte[] buffer = new Byte[ms.Length];
buffer = ms.ToArray();
string xmlOutput = System.Text.Encoding.UTF8.GetString(buffer);
//The next 3 line works fine but it will remove the Indent from the XmlWriterSettings
//TextReader tr = new StreamReader(ms);
//ms.Seek(0, SeekOrigin.Begin);
//xmlOutput = tr.ReadToEnd() + "";
//Can't nload the xmlOutput from buffer
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlOutput);
return xmldoc;
}
The XmlWriter is writing a utf-8 byte-order mark to the stream. Encoding.UTF8.GetString doesn't account for this (since it's only supposed to occur in files) so the first character of the string becomes an invalid, unprintable character, which is what XmlDocument.LoadXml chokes on.
EDIT: Since you said you want to create an XmlDocument so you can reuse it, I recommend one of the following:
If using .Net 3.5 or newer, use XDocument which is much easier to use (I recommend this).
Create the XmlDocument directly by constructing nodes and adding them to the tree.
Create the XmlDocument directly from the writer by using XPathNavigator (XmlWriter writer = doc.CreateNavigator.AppendChild())
Note that you can't easily add insignificant whitespace to an XmlDocument. Using XDocument and writing it to the output using doc.Save(Response.Output) is by far the easiest option if you want to have nicely formatted output.
I have a method which loops through an XML document using an XMLReader (validating at the same time) extracting specific pieces of information. I also need to compress the entire XML document in preparation for storing it in a database. The code I have to do this is below. Is this (passing the entire XmlReader to StreamWriter.Write()) the appropriate / most efficient way to achieve this? I didn't see a clear way to use the while(validatingReader.Read()) loop to achieve the same result.
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add("schemaNamespace", "schemaLocation");
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ValidationType = ValidationType.Schema;
readerSettings.Schemas.Add(schemaSet);
readerSettings.ValidationEventHandler
+= new ValidationEventHandler(XMLValidationError);
using (XmlReader documentReader = requestXML.CreateNavigator().ReadSubtree())
{
using (XmlReader validatingReader =
XmlReader.Create(documentReader, readerSettings))
{
using (MemoryStream output = new MemoryStream())
{
using (DeflateStream gzip =
new DeflateStream(output, CompressionMode.Compress))
{
using (StreamWriter writer =
new StreamWriter(gzip, System.Text.Encoding.UTF8))
{
writer.Write(validatingReader);
this.compressedXMLRequest
= Encoding.UTF8.GetString(output.ToArray());
}
}
}
while (validatingReader.Read())
{
// extract specific element contents
}
}
}
Compression portion looks fine. MemoryStream may not be the best choice for large documents, but check if performance is ok for your scenarios before changing.
"extract specific element" portion will not read anything as reader is forward only, so all content is already read by the time that portion is executed. You may want to recreate the reader.
For future reference:
The code in the Question does not work properly. Passing an XmlReader to a StreamWriter doesn't work as expected. In the end I didn't end up combining compression with validation in this way so I don't exactly have "correct" code to show for this but didn't want to leave the question dangling.
I had a Dataset with some data in it. When I tried to write this DataSet into a file, everything was OK. But When I tried to write it into a MemoryStream, the XML file declaration was lost.
The code looks like:
DataSet dSet = new DataSet();
//load schema, fill data in
dSet.WriteXML("testFile.xml");
MemoryStream stream = new MemoryStream();
dSet.WriteXML(stream);
stream.Seek(0,SeekOrigin.Begin);
When I opened file testFile.xml, I got:
<?xml version="1.0" standalone="yes"?>
//balabala
But When I open the stream with StreamReader, I only got:
//balabala
Somebody said I can insert XML file declaration in my stream manually. It works but seems so ugly. Do you know why it dropped the first line and any more simple solution?
It wasn't dropped. Simply not included. Though it is highly recommend the xml declaration is not a required element of the xml specification.
http://msdn.microsoft.com/en-us/library/ms256048(VS.85).aspx
You can use XmlWriter.WriteStartDocument to include the xml declaration in the stream like so:
MemoryStream stream = new MemoryStream();
var writer = XmlWriter.Create(stream);
writer.WriteStartDocument(true);
dSet.WriteXML(stream);
I try your solution with DataTable and don't work correctly.
using (MemoryStream stream = new MemoryStream()) {
using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8)) {
writer.WriteStartDocument(); //<?xml version="1.0" encoding="utf-8"?>
writer.WriteRaw("\r\n"); //endline
writer.Flush(); //Write immediately the stream
dTable.WriteXml(stream);
}
}
If you disassemble the 2.0 code you'll see that the WriteXml method that takes a file name explictly writes out the declaration (XmlWriter.WriteStartDocument) but the WriteXml methods that take a stream or writer do not.