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";
}
}
Related
From the following xml:
<response>
<content>
<Result xmlns="http://www.test.com/nav/webservices/types">
<Name>Test</Name>
</Result>
</content>
<status>ok</status>
</response>
I am trying to get the value of the Name element the following way but that does not work:
private static void Main()
{
var response = new XmlDocument();
response.Load("Response.xml");
var namespaceManager = new XmlNamespaceManager(response.NameTable);
namespaceManager.AddNamespace("ns", "http://www.test.com/nav/webservices/types");
Console.WriteLine(response.SelectSingleNode("/response/content/Result/Name", namespaceManager).InnerXml);
}
How can I select the Name element?
Your code would have worked just fineif the Xml had defined the namespace with a "ns:" prefix.
But in this case, the namespace is given without any prefix, which sets the default namespace for everything in the Result tag to ".../webservice/types".
To reflect this, you need to modify the Xpath, and tell the XmlDocument that the nodes you are looking for under Resultare in the webservice/types namespace. So your query will look like this:
Console.WriteLine(response.SelectSingleNode(#"/response/content/ns:Result/ns:Name", namespaceManager).InnerXml);
For getting directly the text value of a node there is a text() function, if used in the query it would look like:
/response/content/Result/Name/text()
Try this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.InnerXml = "<response><content><Result xmlns=\"http://www.test.com/nav/webservices/types\"><Name>Test</Name></Result></content><status>ok</status>";
string elementValue = String.Empty;
if (xmlDoc != null)
{
xNode = xmlDoc.SelectSingleNode("/Result");
xNodeList = xNode.ChildNodes;
foreach (XmlNode node in xNodeList)
{
elementValue = node.InnerText;
}
}
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();
I want to use a xml file which is as below
<?xml version="1.0" encoding="utf-8" ?>
<pages>
<page name="Default.aspx">
<method name="Login_click">
<message code="0" description="this is a test description">
<client code="0000000000" description="this is a description for clent 0000000000" />
</message>
</method>
</page>
</pages>
Now I want to create a function like below
public static string GetAppMessage(string pageName, string methodName, string clientCode, string code)
{
var xmlFile = HttpContext.Current.Server.MapPath("~/App_Data/Theme.xml");
var doc = new XmlDocument();
doc.Load(xmlFile);
if (string.IsNullOrEmpty(clientCode))
{
//go to node who page name to pageName
//and read the vlue
}
else
{
//read for a particular client code
}
}
How can I do this.
Edit 1
Do I need to loop through each node or can I reach to a particular node directly and find the decedent nodes.
like below
foreach (XmlNode chldNode in doc.ChildNodes)
{
....
Instead of XmlDocument you can use XDocument and LINQ to xml:
var xmlFile = HttpContext.Current.Server.MapPath("~/App_Data/Theme.xml");
XDocument xmlDoc = XDocument.Load(xmlFile);
var xmlPage = (from page in xmlDoc.Descendants()
where page.Name.LocalName == "page"
&& page.Attribute("name").Value == pageName
select page).FirstOrDefault();
if (xmlPage != null)
{
//do what you need
}
When you use XmlDocument and you know how the XML-file will look like (I mean you know the names of the nodes where the information is inside) then you could do something like this:
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlElement root = doc["NameOfRootNode"];
if (root != null)
{
//For nodes you just need to bypass to get to another subnode:
XmlNode node = root.SelectSingleNode("nameOfAnotherNode");
//For nodes you actually want to do something with, like read text, attribute etc.
if (node != null && node.SelectSingleNode("nameOfOneMoreNode") != null)
{
var xmlElement = node["nameOfOneMoreNode"];
if (xmlElement != null)
{
//Read from the xmlElement you selected and do something with it...
}
}
//...
}
With SelectSingleNode or SelectNodes you can maneuver to a specific known node and can read the InnerText or an Attribute.
You can use XPath to get <page> element by it's name attribute, for example :
string xpath = "//page[#name='{0}']";
XmlNode page = doc.SelectSingleNode(string.Format(xpath, pageName));
//and read the vlue
Basically, above XPath look for <page> element having name attribute equals pageName parameter.
my xml stored in xml file which look like as below
<?xml version="1.0" encoding="utf-8"?>
<metroStyleManager>
<Style>Blue</Style>
<Theme>Dark</Theme>
<Owner>CSRAssistant.Form1, Text: CSR Assistant</Owner>
<Site>System.ComponentModel.Container+Site</Site>
<Container>System.ComponentModel.Container</Container>
</metroStyleManager>
this way i am iterating but some glitch is there
XmlReader rdr = XmlReader.Create(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + #"\Products.xml");
while (rdr.Read())
{
if (rdr.NodeType == XmlNodeType.Element)
{
string xx1= rdr.LocalName;
string xx = rdr.Value;
}
}
it is always getting empty string xx = rdr.Value;
when element is style then value should be Blue as in the file but i am getting always empty....can u say why?
another requirement is i want to iterate always within <metroStyleManager></metroStyleManager>
can anyone help for the above two points. thanks
Blue is the value of Text node, not of Element node. You either need to add another if to get value of text nodes, or you can read inner xml of current element node:
rdr.MoveToContent();
while (rdr.Read())
{
if (rdr.NodeType == XmlNodeType.Element)
{
string name = rdr.LocalName;
string value = rdr.ReadInnerXml();
}
}
You can also use Linq to Xml to get names and values of root children:
var xdoc = XDocument.Load(path_to_xml);
var query = from e in xdoc.Root.Elements()
select new {
e.Name.LocalName,
Value = (string)e
};
You can use the XmlDocument class for this.
XmlDocument doc = new XmlDocument.Load(filename);
foreach (XmlNode node in doc.ChildNodes)
{
if (node.ElementName == "metroStyleManager")
{
foreach (XmlNode subNode in node.ChildNodes)
{
string key = subNode.LocalName; // Style, Theme, etc.
string value = subNode.Value; // Blue, Dark, etc.
}
}
else
{
...
}
}
you can user XDocument xDoc = XDocument.Load(strFilePath) to load XML file.
then you can use
foreach (XElement xeNode in xDoc.Element("metroStyleManager").Elements())
{
//Check if node exist
if (!xeNode.Elements("Style").Any()
//If yes then
xeNode.Value
}
Hope it Helps...
BTW, its from System.XML.Linq.XDocument
Here is the XML sample:
<?xml version="1.0" ?>
<XMLScreen xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CX>80</CX>
<CY>24</CY>
<Formatted>true</Formatted>
<Field>
<Location position="1" left="1" top="0" length="69" />
<Attributes Base="226" Protected="false" FieldType="High" />
*SDC SCHEDULING CATEGORY UPDATE
</Field>
</XMLScreen>
I want to retrive the Inner text of each field based on its Location position.
What I have so far is:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(myEm.CurrentScreenXML.GetXMLText());
XmlNodeList fields = xmlDoc.GetElementsByTagName("Field");
MessageBox.Show("Field spot: " + i + " Contains: " + fields[i].InnerText);
And I want to be able to just extract the inner text of the field by passing in a number of the location position. So if I say foo[i] I want to be able to get the innertext
*SDC SCHEDULING CATEGORY UPDATE
You should use a xpath search query :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
int nodeId = 4;
XmlNode node = xmlDoc.SelectSingleNode(String.Format(#"//Location[#position='{0}']", nodeId));
if (node != null)
{
String field = node.ParentNode.InnerText;
}
Something like that, with XDocument instead of XmlDocument (well, if you're not in .net 3.5 or higher, we'll have a problem).
private string GetTextByLocationId(XDocument document, int id)
{
var field = document.Descendants("Field").FirstOrDefault(m => m.Element("Location").Attribute("position").Value == id.ToString());
if (field == null) return null;
return field.Value;
}
and usage
var xDocument = XDocument.Load(<pathToXmlFile or XmlReader or string or ...>);
var result = GetTextByLocationId(xDocument, 1);
EDIT
or if you want a dictionary with :key = position / value = text
private static Dictionary<int, string> ParseLocationAndText(XDocument document)
{
var fields = document.Descendants("Field");
return fields.ToDictionary(
f => Convert.ToInt32(f.Element("Location").Attribute("position").Value),
f => f.Value);
}
Try,
XElement root = XElement.Parse(myEm.CurrentScreenXML.GetXMLText());
XElement field = root.XPathSelectElement(
string.Format("Field[Location/#position='{0}']", 1));
string text = field.Value;
You will need to use the following using to use XPath with XElements.
using System.Xml.XPath;