Retrieve values from XML File - c#

I have Multiple XML Files that look like below
<?xml version="1.0" encoding="UTF-8"?>
<schema>
<sp_transaction_id name="sp_transaction_id" value="1" />
<sp_year name="sp_year" value="2015" />
<sp_first_name name="sp_first_name" value="James" />
<sp_gender name="sp_gender" value="Male" />
<sp_date_of_birth name="sp_date_of_birth" value="06-06-1999" />
</schema>
The XML Format i think is in Key-Value Pairs.
I want to extract these values and store it into a database(SQL Server 2012) table, with the name(eg; sp_year) as Column Name and value(eg; 2015) as the Column value using ASP.NET C#.
I think i can upload the file and read it like this :
string fileName = Path.GetFileName(FileUpload1.PostedFile.FileName);
string filePath = Server.MapPath("~/Uploads/") + fileName;
FileUpload1.SaveAs(filePath);
string xml = File.ReadAllText(filePath);
But thats pretty much it ( Sorry Im a beginner ). Please Guide me. Thanks

You can use the following code to get the key value pairs
XDocument doc = XDocument.Load(filePath);
var schemaElement = doc.Element("schema");
foreach (var xElement in schemaElement.Elements())
{
Console.WriteLine(xElement.Attribute("name").Value + ":" + xElement.Attribute("value").Value);
}
Elements method returns all elements inside schema element.
However I suggest changing xml file to this format, if possible
<?xml version="1.0" encoding="UTF-8"?>
<schema>
<KeyValuePair name="sp_transaction_id" value="1" />
<KeyValuePair name="sp_year" value="2015" />
<KeyValuePair name="sp_first_name" value="James" />
<KeyValuePair name="sp_gender" value="Male" />
<KeyValuePair name="sp_date_of_birth" value="06-06-1999" />
</schema>

For reading data from an xml file you don't need to upload it.You can give path of xml and read from it.You can use following method to read from xml
public static XmlDocument LoadXmlDocument(string xmlPath)
{
if ((xmlPath == "") || (xmlPath == null) || (!File.Exists(xmlPath)))
return null;
StreamReader strreader = new StreamReader(xmlPath);
string xmlInnerText = strreader.ReadToEnd();
strreader.Close();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlInnerText);
return xmlDoc;
}
For reading data from xml you can use
XmlDocument xmlDoc = LoadXmlDocument(xmlPath);
XmlNodeList nodes = xmlDoc .SelectNodes("//*");
foreach (XmlElement node in nodes)
{
.
.
.
}
In foreach loop you can get your required values e.g sp_year

The answer below shows how to create an XmlDocument from it.
I would suggest to use it as a User-Defined class if you know whether Xml schema change.
First of all you should create POCO class appropriate to Xml file schema using XmlAnnotations.
Secondly:
Having path of the file:
XmlSerializer serializer = new XmlSerializer(typeof(definedclass));
using (FileStream fs = File.Open(pathtofile))
using (XmlReader reader = XmlReader.Create(fs))
{
var xmlObject = serializer.Deserialize(reader);
}
xmlObject is now your user-defined class with values from xml.
Regards,
Rafal

You can load the files into an XDocument & then use Linq-To-XML to extract the required information. The example code below loads all name/value pairs into an array of class :
class MyXMLClass
{
public String FieldName { get; set; }
public String Value { get; set; }
}
The code gets all "schema" descendants (just one as it is the top level element), then selects all elements inside the & creates a new class object for each extracting the name & value.
XDocument xd = XDocument.Load("test.xml");
MyXMLClass[] xe =
xd.Descendants("schema")
.Elements()
.Select(n => new MyXMLClass {FieldName = n.Attribute("name").Value, Value = n.Attribute("value").Value})
.ToArray();

Related

how to read XML file and change some value

Xml file :
<configuration>
<work.config>
<variable name="A" value="001" />
<variable name="B" value="002" />
<variable name="C" value="003" />
</work.config>
</configuration>
and next I write some code to read XML
XmlDocument cc = new XmlDocument();
cc.Load("wc.config");
XmlNodeList wc_value = cc.SelectNodes("configuration/work.config[#name='A']");
foreach (XmlNode wc_text in wc_value)
{
String Text2 = wc_text.InnerText;
}
but Text2 is null; why, and how do I have it not null?
And next I want to change name="B" value="999", how do I do that?
Your variable elements dont not have text, that's the reason you are getting null.
Your variable elements have 2 attributes: name and value.
In order to get the value of the attribute:
string txt = wc_text.Attributes["name"].Value
Set value:
wc_text.Attributes["name"].Value = "foo".
Your problem begins in this line.
"configuration/work.config[#name='A']"
work.config attribute doesn't have an attribute called name. Following is what you actually required.
"configuration/work.config/variable[#name='A']"
Similarly, with the path fixed as above, the following line would still return empty string as you are reading the InnerText of the node.
String Text2 = wc_text.InnerText;
What you would need is to read the Value attribute of the node.
String Text2 = wc_text.Attributes["value"].Value;
If your intention is to Read and Update Value Attribute of a particular node, an easier approach would be to use XDocument.
// Assuming there are no duplicate names. You need to change accordingly the Queries if there are duplicates
public void UpdateKey(XDocument document,string key,string value)
{
var node = document.Descendants("variable").First(x=>(string)x.Attribute("name")==key);
node.Attribute("value").Value = value;
}
public string ReadKey(XDocument document, string key)
{
return document.Descendants("variable").First(x=>(string)x.Attribute("name")==key).Attribute("value").Value;
}
Now, you could use it as
XDocument doc = XDocument.Load(xml);
var ValueOfA = ReadKey(doc,"A");
var oldValueOfB = ReadKey(doc,"B");
UpdateKey(doc,"B","999");
var newValueOfB = ReadKey(doc,"B");
LINQ to XML
void Main()
{
XDocument xmlDoc = XDocument.Load(#"e:\temp\wc.config");
// read attributes
foreach (var leaf in xmlDoc.Descendants("variable"))
{
Console.WriteLine(leaf.Attributes("name").FirstOrDefault().Value);
Console.WriteLine(leaf.Attributes("value").FirstOrDefault().Value);
}
// modify value of the attribute
var attr = xmlDoc.Descendants("variable")
.Where(d => (string)d.Attribute("name").Value == "B");
attr.Attributes("value").FirstOrDefault().Value = "999";
}
You could use LINQ to XML to get or set value of any element or attribute based on condition as below:
include namespace System.Xml.Linq in your using directives to use XDocument
XDocument doc = XDocument.Load("wc.config");
foreach (XElement variableElement in doc.Descendants("variable"))
{
if (variableElement.Attribute("name").Value == "A")
{
variableElement.Attribute("value").Value = "";
}
else if (variableElement.Attribute("name").Value == "B")
{
variableElement.Attribute("value").Value = "999";
}
}
Use XPath language:
var xmlString = #"<configuration>
<work.config>
<variable name='A' value='001' />
<variable name='B' value='002' />
<variable name='C' value='003' />
</work.config>
</configuration>";
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xmlString);
var variables = xmlDocument.SelectSingleNode("//variable");
Try below code
XmlDocument doc = new XmlDocument();
doc.Load("C:\\config.xml");
XmlNodeList list= doc.SelectNodes("configuration/work.config/variable");
foreach (XmlNode item in list)
{
if (item.Attributes["name"].InnerText == "B")
{
item.Attributes["value"].InnerText = "999";
}
}

How to get Xml tags from log file

I have a log file sample in which i have a error message plus xml tags eg
error message
xmltag
error message
xml tag
problem is i only want to get xml tag but i am getting error "Data at the root level is invalid."
c# code is
XmlDocument xDoc = new XmlDocument();
xDoc.Load("C:\\Users\\qadeer.hussain\\Desktop\\gw-msg.log");
var nodes = xDoc.GetElementsByTagName("Message");
var resultNodes = new List<XmlNode>();
foreach(XmlNode node in nodes )
{
if (node.Attributes != null && node.Attributes["Receiver"] != null && node.Attributes["Receiver"].Value == "+921215648545")
{
resultNodes.Add(node);
}
}
xml file is
some value
some value
<Message type="email">
<Details locale="en">
<Part type="plain" id="email/plain/User.ResetPassword.email"/>
</Details>
<Subject>New Password</Subject>
<Sender>BB.Ops#example.com</Sender>
<Context>
<Parameter name="pswr" value="00"/>
<Receiver>a.k#example.com</Receiver>
some value
some value
<Message type="email">
<Details locale="en">
<Part type="plain" id="email/plain/User.ResetPassword.email"/>
</Details>
<Subject>New Password</Subject>
<Sender>BB.Ops#example.com</Sender>
<Context>
<Parameter name="pswr" value="00"/>
</Context>
<Receiver>a.k#example.com</Receiver>
</Message>
As mentioned, the file is not xml. You need to read each line and determine if it's part of the xml or part of the message. As the xml isn't on a single line and the messages can be any length, this may be a bit hit-and-miss.
One possible solution, which works only for the example you've provided, would be something like:
var filename = "...";
var xmlText = new StringBuilder();
bool isXml = false;
foreach (var line in System.IO.File.ReadLines(filename))
{
if (line.Trim().StartsWith("<Message"))
isXml = true;
if (isXml)
{
xmlText.Append(line);
if (line.Trim().EndsWith("</Message>"))
{
//var xdoc = XDocument.Parse(xmlText.ToString());
var xdoc = new XmlDocument();
xml.LoadXml(xmlText.ToString());
//process xml here
xmlText.Clear();
isXml = false;
}
}
}
If you can change the output format of the log file, I'd recommend that to make parsing so much easier, eg add a line before and after the xml with just the text [XML] then you can look for that token.
Edit: Update to use XmLDocument rather than XDocument.
You seem to be trying to load the entire log file as XML:
XmlDocument xDoc = new XmlDocument();
xDoc.Load("C:\\Users\\qadeer.hussain\\Desktop\\gw-msg.log");
That's not going to work, because the log file isn't an XML file - it's a text file that just happens to contain some XML.
You'll need to parse the log file and extract the XML in order to load it with XmlDocument - there are many ways of parsing text files, without more knowledge of your problem domain I won't go into those details here.

Read then write html to xml file using linq xml and xml writer

I am reading the Value of a element <content>Text with <br /> break</content> into a string and showing that string in a TextBox. Afterwards the user can modify it possibly with additional HTML tags. Upon using linq to query the exact node to insert the user-input all spiky bracket <> from html tags are normalized into <br />. So how do I preseve my html tags?
I already read and tried the solutions from these questions but I failed to apply it to my use case:
c# XML avoid html encode using XDocument
Get html tags embedded in xml using linq
Keep HTML tags in XML using LINQ to XML
http://blogs.msdn.com/b/charlie/archive/2008/09/29/linq-farm-preserving-formats-with-linq-to-xml.aspx
This is an example of my xml file:
<events>
<event id="0">
<content><br/></content>
</event>
</events>
How I load and query:
XDocument xml;
XmlTextReader xtr = new XmlTextReader(this.pathXML);
xtr.Normalization = false;
xml = XDocument.Load(xtr, LoadOptions.PreserveWhitespace);
xtr.Close();
var nodeToEdit = xml.Descendants("event").Where(x => (string)x.Attribute("id") == "0");
How I manipulate my xml file with user input:
string userinput = "Text with <br /> break"; // This is read from TextBox control inside Form
foreach (var item in nodeToEdit.Elements())
{
if(item.Name == "content")
{
item.Value = userinput;
}
}
How I save:
changeSaveIndent(xml, this.pathXML);
public static void changeSaveIndent(XDocument x, string path)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
// Indent by tab. Can be changed to " " or similar
settings.IndentChars = "\t";
using (XmlWriter writer = XmlTextWriter.Create(path, settings))
{
x.Save(writer);
}
}
My expected xml output file should look like this:
<events>
<event id="0">
<content>Text with <br /> break</content>
</event>
</events>
sorry for the long post..
Replace this:
if(item.Name == "content")
{
item.Value = userinput;
}
with this:
if(item.Name == "content")
{
item.ReplaceWith(XElement.Parse("<content>" + userinput + "</content>"));
}
Just note that your user input will have to be valid XML for this to work. If not, you'd probably be best off breaking out the call to XElement.Parse into a try catch block or just adding the input as unescaped CDATA, like so:
if (item.Name == "content")
{
item.Value = "";
item.Add(new XCData(userinput));
}
Which would produce XML that looks like this:
...
<content><![CDATA[Text with <br /> break]]></content>
...
Based on what you are describing, I would say that you are using the wrong format in your XML file. <br/> isn't describing a new node in the XML file at all, you are using it as part of content, and therefore it should be encoded. But that said, if you must retrieve and set the content node like you describe, you want .InnerXml, not .Value or .Text or .InnerText

How to get a specific XML value from an XML using C#?

I have the below XML as:
<Requests xmlResponse="true">
<Request response="yes" responsewait="120000" sequence="1" type="Fulfillment">
<RequestData>
<PrintControl>FTP</PrintControl>
<User>81DF</User>
<Documents>
<AddressChangeLetter>
<DocumentInfo>
<AddressChange AddressChangeId="109346" Branch="418" LastChangeDate="">
<Name>AAA NOVAK</Name>
<TaxID>123123121</TaxID>
<OldAddress1>BOX 216</OldAddress1>
<OldAddress2>NYANE 68017</OldAddress2>
<OldAddress3 />
<OldAddress4 />
<NewAddress1>P O BOX 216</NewAddress1>
<NewAddress2>CERESCO NE 68017</NewAddress2>
<NewAddress3 />
<NewAddress4 />
<DateChanged>05/08/2013</DateChanged>
<AccountInfo AcctNum="231232311" AcctStatusCodes="IX" />
</AddressChange>
</DocumentInfo>
</AddressChangeLetter>
</Documents>
</RequestData>
I wanted to get the name or the value which is under the tag "Documents". Since in the above XML, the tag under the "Document" tag is "AddressChangeLetter", therefore, I want to get this name. How will I do it.
Something along the lines of... (it's not perfect, but it'll get you started - Google the functions I've used to get it working properly):
XmlDocument xml = new XmlDocument();
xml.Load(yourPathGoesHere)
XmlNodeList addressNodes = xml.GetElementsByTagName("AddressChange");
foreach (XmlNode oneNode in addressNodes) {
myVariableToGrabNames = oneNode["Name"].InnerText;
}
This can be done pretty easily using Linq to XML e.g.
var xml = ...;
var xdoc = XDocument.Parse(xml);
foreach (var e in xdoc.Descendants("Documents").Elements())
{
var name = e.Name; // AddressChangeLetter
}

How to parse XML file to get specific data effectively

I have an XML file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<PathMasks>
<Mask desc="Masks_X1">
<config id="01" mask="88" />
<config id="03" mask="80" />
<config id="51" mask="85" />
</Mask>
<Mask desc="Masks_X2">
<config id="70" mask="1" />
<config id="73" mask="6" />
</Mask>
<Types>
<path id="01" desc="TC->PP1" />
<path id="02" desc="TC->PP2" />
<path id="03" desc="TC->PPn" />
</Types>
</PathMasks>
How to parse the file and get all the data of Mask_X1 as following:
id value
=====
01, 88
03, 80
51, 85
The .NET framework I am using is 2.0
As you're working with .Net 2.0 you won't have Linq and will therefore need to use XPath, this sample should help you out.
XmlDocument doc = new XmlDocument();
doc.Load(pathToXmlDoc);
XmlNode node = doc.SelectSingleNode("/PathMasks/Mask[#desc='Masks_X1']");
foreach (XmlNode config in node)
{
Console.WriteLine("{0}\t{1}",
config.Attributes["id"].Value,
config.Attributes["mask"].Value);
}
Using XmlDocument (slower, larger memory footprint, read/write, works the same way XML DOMs everywhere work):
XmlDocument d = new XmlDocument();
d.Load(filename);
string xpath = "/PathMasks/Mask[#desc='Mask_X1']/config"
foreach (XmlElement elm in d.SelectNodes(xpath))
{
Console.WriteLine(elm.GetAttribute("id"), elm.GetAttribute("desc"));
}
Using XPathDocument (faster, smaller memory footprint, read-only, weird API):
XPathDocument d = new XPathDocument(filename);
string xpath = "/PathMasks/Mask[#desc='Mask_X1']/config"
XPathNodeIterator iter = d.CreateNavigator().Select(xpath);
while (iter.MoveNext())
{
Console.WriteLine(iter.Current.GetAttribute("id"), iter.Current.GetAttribute("desc'));
}
I'm sure there's a perfectly good reason why there isn't a method of XPathNavigator that returns an IEnumerable<XPathNavigator> so that you can iterate over the results of an XPath query like a normal person, but I haven't been able to work it out.
Using Linq to XML :
XDocument doc = XDocument.Load(filename);
var query = from mask in doc.Root.Elements("Mask")
where mask.Attribute("desc").Value == "Masks_X1"
from config in mask.Elements("config")
select new
{
id = config.Attribute("id").Value,
value = config.Attribute("mask").Value
};
foreach(var mask in query)
{
Console.WriteLine("{0}\t{1}", mask.id, mask.value);
}
Use XDocument and query into it with Linq to XML
XDocument doc = XDocument.Load("file.xml");
var linqtoxml = from node in document.Descendants("Mask")
where (string)node.Attribute("desc").Value == "Masks_X1"
select node;
foreach (var mask in linqtoxml)
{
// pull data out of here into a structure of your choosing
}

Categories

Resources