I'm reading a file like from the web:
<?xml version='1.0' encoding='UTF-8'?>
<eveapi version="2">
<currentTime>2011-07-30 16:08:53</currentTime>
<result>
<rowset name="characters" key="characterID" columns="name,characterID,corporationName,corporationID">
<row name="Conqrad Echerie" characterID="91048359" corporationName="Federal Navy Academy" corporationID="1000168" />
</rowset>
</result>
<cachedUntil>2011-07-30 17:05:48</cachedUntil>
</eveapi>
im still new to XML and i see there are many ways to read XML data, is there a certain way im going to want to do this? what i want to do is load all the data into a StreamReader? and then use get; set; to pull the data later?
If you want object-based access, put the example xml in a file and run
xsd.exe my.xml
xsd.exe my.xsd /classes
this will create my.cs which is an object model similar to the xml that you can use with XmlSerializer:
var ser = new XmlSerializer(typeof(eveapi));
var obj = (eveapi)ser.Deserialize(source);
Use XmlReader Class or XmlTextReader Class
http://msdn.microsoft.com/en-us/library/aa720470(v=vs.71).aspx
http://msdn.microsoft.com/en-us/library/system.xml.xmltextreader(v=vs.71).aspx
If you need to use the data in the easy way, especially when you're new to XML, use XmlDocument.
To load the document:
using System.Xml;
using System.IO;
public class someclass {
void somemethod () {
//Initiate the XmlDocument object
XmlDocument xdoc;
//To load from file
xdoc.Load("SomeFolder\\SomeFile.xml");
//Or to load from XmlTextReader, from a file for example
FileStream fs = FileStream("SomeFolder\\SomeFile.xml", FileMode.Open, FileAccess.Read);
XmlTextReader reader = new XmlTextReader(fs);
xdoc.Load(reader);
//In fact, you can load the stream directly
xdoc.Load(fs);
//Or, you can load from a string
xdoc.LoadXml(#"<rootElement>
<element1>value1</element1>
<element2>value2</element2>
</rootElement>");
}
}
I personally find XmlDocument far easier to use for navigating an Xml file.
To use it efficiently, you need to learn XPath. For example, to get the name of the first row:
string name = xdoc.SelectSingleNode("/eveapi/result/rowset/row").Attribute["name"].InnerText;
or even more XPath:
string name = xdoc.SelectSingleNode("/eveapi/result/rowset/row/#name").InnerText;
you can even filter:
XmlNodeList elems = xdoc.SelectNodes("//*[#name=\"characters\"]")
gives you the rowset element.
But that's off topic.
Related
I have a C# service where I loop every 1 seconds trough a directory looking for XML files.
These XML files may look like this:
<?xml version="1.0" encoding="UTF-8"?>
<job>
<type>freelance</type>
<text>blah</text>
</job>
In a foreach I do the following:
var doc = new XmlDocument();
doc.LoadXml(xmlFile);
XmlNode xmltype = doc.DocumentElement.SelectSingleNode("/job/type");
And than I would like to use these strings to use in my program, however. Using xmltype.InnerText does not work. Documentation on MSDN does not provide me with anything new and I would like to know what I am doing wrong.
First you have to check the xml file.whether is there any data or not.
after that take the one particular node check for innerText.
for example
This is the Text
XmlNode xmlType = doc.DocumentElement.SelectSingleNode("/job/type");
xmlType.innerText = "This is the Text";
xmlType.Value = "Stack";
This following console program will output "freelance". I think the issue may be with some of your XML - do all of your XML docs follow the same schema? I am guessing that the code fails with a NullReferenceException at some point. I've added a null check to protect against this possible scenario.
To help debug your service I tend to use the technique described here to run the app as console application (for easy debugging) or windows service.
using System;
using System.Xml;
public class Program
{
static string xmlFile = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<job>
<type>freelance</type>
<text>blah</text>
</job>";
public static void Main()
{
var doc = new XmlDocument();
doc.LoadXml(xmlFile);
XmlNode xmltype = doc.DocumentElement.SelectSingleNode("/job/type");
if(xmltype==null)
{
Console.WriteLine("/job/type not found");
} else {
Console.WriteLine(xmltype.InnerText);
}
}
}
Try this:
string str = xmltype.Value;
I have to generate specific XML data from code.
The XML needs to look like this
<this:declarationIdentifier xmlns:this="demo.org.uk/demo/DeclarationGbIdentifier"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd"
xmlns:nsIdentity="demo.org.uk/demo/DeclarationGbIdentityType">
<this:declarationIdentity>
<nsIdentity:declarationUcr>Hello World</nsIdentity:declarationUcr>
</this:declarationIdentity>
</this:declarationIdentifier>
I have dabbled with XmlSerializer and XDocument but cant get the output to match this exactly
Please help.
I believe this will produce your desired output. There possibly is a simpler way this is just off the cuff to get you started. With the prefixes that you are requiring I would look up XmlDocument and adding namespaces to it to have a better understanding of what the code below is doing. Also what I would do is attempt to acquire the XSD schema file and use the XSD.exe to build a .cs file and then you can move forward with the XmlSerializer. If you move forward with the code below i highly suggest moving off your namespaceuri's into some soft of settings file so you can easily modify them in the event they change.
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("this", "declarationIdentifier", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:this", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
//Just setting an Attribute of xsi:schemaLocation it would always drop the xsi prefix in the xml so this is different to accomodate that
XmlAttribute schemaAtt = doc.CreateAttribute("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
schemaAtt.Value = "demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd";
root.Attributes.Append(schemaAtt);
root.SetAttribute("xmlns:nsIdentity", "demo.org.uk/demo/DeclarationGbIdentityType");
doc.AppendChild(root);
XmlElement declarationIdentity = doc.CreateElement("this", "declarationIdentity", "demo.org.uk/demo/DeclarationGbIdentifier");
XmlElement declarationUcr = doc.CreateElement("nsIdentity","declarationUcr","demo.org.uk/demo/DeclarationGbIdentityType");
declarationUcr.InnerText = "Hello World";
declarationIdentity.AppendChild(declarationUcr);
doc.DocumentElement.AppendChild(declarationIdentity);
To output this as a string or dump it off to a file you can use the following operations, I output to a file as well as output to the console in my test app.
using (var stringWriter = new StringWriter())
using (StreamWriter writer = new StreamWriter(#"C:\<Path to File>\testing.xml"))
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
writer.Write(stringWriter.GetStringBuilder().ToString());
Console.WriteLine(stringWriter.GetStringBuilder().ToString());
}
I'm trying to find the most reasonable way to open a file, modify its content and then write it back to file.
If I have the following "MyFile.xml"
<?xml version="1.0" encoding="utf-8"?>
<node>
<data>this is my data which is long</data>
</node>
And then want to modify it according to this:
private static void Main(string[] args)
{
using (FileStream stream = new FileStream("Myfile.xml", FileMode.Open))
{
XDocument doc = XDocument.Load(stream);
doc.Descendants("data").First().Value = "less data";
stream.Position = 0;
doc.Save(stream);
}
}
I get the following result. Note that, since the total file length is less than before I get incorrect data at the ending.
<?xml version="1.0" encoding="utf-8"?>
<node>
<data>less data</data>
</node>/node>
I guess I could use File.ReadAll* and File.WriteAll* but that would mean two File openings. Isn't there some way to say "I want to open this file, read its data and when I save delete the old content" without closing and reopening the file? Other solutions that I have found include FileMode.Truncate, but that would imply that I cannot read the content.
You'll have to use FileStream.SetLength like this:
stream.SetLength(stream.Position);
After you have finished writing.
Of course, assuming that the position is at the end of the written data.
Why do you read the file into a filestream first?
You can do the following:
private static void Main(string[] args]
{
string path = "MyFile.xml";
XDocument doc = XDocument.Load(path);
// Check if the root-Node is not null and other validation-stuff
doc.Descendants("data").First().Value = "less data";
doc.Save(path);
}
The problem with the stream is, that you can either read or write.
I've read, that with the .net-Framework 4.5 it's also possible to read and write on a stream, but haven't tried it yet.
I'm trying to create an XML with multiple root elements. I can't change that because that is the way I'm supposed to send the XML to the server. This is the error I get when I try to run the code:
System.InvalidOperationException: This operation would create an incorrectly structured document.
Is there a way to overwrite this error and have it so that it ignores this?
Alright so let me explain this better:
Here is what I have
XmlDocument doc = new XmlDocument();
doc.LoadXml(_application_data);
Now that creates the XML document and I can add a fake root element to it so that it works. However, I need to get rid of that and convert it into a DocumentElement object.
How would I go about doing that?
Specify Fragment when creating XmlWriter as shown here
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.CloseOutput = false;
// Create the XmlWriter object and write some content.
MemoryStream strm = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(strm, settings))
{
writer.WriteElementString("orderID", "1-456-ab");
writer.WriteElementString("orderID", "2-36-00a");
writer.Flush();
}
If it has multiple root elements, it's not XML. If it resembles XML in other ways, you could place everything under a root element, then when you send the string to the server, you just combine the serialized child elements of this root element, or as #Austin points out, use an inner XML method if available.
just create an XML with single root then get it's content as XML text.
you are talking about XML fragment anyways, since good xml has only one root.
this is sample to help you started:
var xml = new XmlDocument();
var root = xml.CreateElement("root");
root.AppendChild(xml.CreateElement("a"));
root.AppendChild(xml.CreateElement("b"));
Console.WriteLine(root.InnerXml); // outputs "<a /><b />"
I have a string input that i do not know whether or not is valid xml.
I think the simplest aprroach is to wrap
new XmlDocument().LoadXml(strINPUT);
In a try/catch.
The problem im facing is, sometimes strINPUT is an html file, if the header of this file contains
<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
<html xml:lang=""en-GB"" xmlns=""http://www.w3.org/1999/xhtml"" lang=""en-GB"">
...like many do, it actually tries to make a connection to the w3.org url, which i really dont want it doing.
Anyone know if its possible to just parse the string without trying to be clever and checking external urls? Failing that is there an alternative to xmldocument?
Try the following:
XmlDocument doc = new XmlDocument();
using (var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings() {
ProhibitDtd = true,
ValidationType = ValidationType.None
})) {
doc.Load(reader);
}
The code creates a reader that turns off DTD processing and validation. Checking for wellformedness will still apply.
Alternatively you can use XDocument.Parse if you can switch to using XDocument instead of XmlDocument.
I am not sure about the reason behind the problem but Have you tried XDocument and XElement classes in System.Xml.Linq
XDocument document = XDocument.Load(strINPUT , LoadOptions.None);
XElement element = XElement.Load(strINPUT );
EDIT: for xml as string try following
XDocument document = XDocument.Parse(strINPUT , LoadOptions.None );
Use XmlDocument's load method to load the xml document, use XmlNodeList to get at the elements, then retrieve the data ...
try the following:
XmlDocument xmlDoc = new XmlDocument();
//use the load method to load the XML document from the specified stream.
xmlDoc.Load("myXMLDoc.xml");
//Use the method GetElementsByTagName() to get elements that match the specified name.
XmlNodeList item = xDoc.GetElementsByTagName("item");
XmlNodeList url = xDoc.GetElementsByTagName("url");
Console.WriteLine("The item is: " + item[0].InnerText));
add a try/catch block around the above code and see what you catch, modify your code to address that situation.