Error while defining XPathSelectElement c# - c#

I have a complex XML file where I want to retrieve different values from the different Set tag.At the end, i need to take the values to a CSV file.
Please see the xml file format
I am trying to retrieve the value of
<szItemID>3268750004533</szItemID> from the first set
<lMerchandiseStructureID>40</lMerchandiseStructureID> from the second set
<szDesc>PHG VIANDE SECHEE DE</szDesc> from the third set
<dPackingUnitPriceAmount>75</dPackingUnitPriceAmount> from the fourth tag
I have tried to retrieve the first element through the below code but getting an error
NullReferenceException was unhandled
Object reference not set to an instance of an object
Code
XmlDocument document = new XmlDocument();
document.Load(#"D:\\xml_1.xml");
string myXmlString = document.OuterXml.ToString();
XElement xml = XElement.Parse(myXmlString);
Console.WriteLine(string.Format("{0}",xml.XPathSelectElement("/UpdateDB/Transaction/Insert/Set/szItemID").Value));
Please help
StringBuilder dataToBeWritten = new StringBuilder();
var doc = XDocument.Load(#"D:\xml_2.xml");
foreach (var trans in doc.Descendants("Transaction"))
{
var val3 = (string)doc.Descendants("Set").Elements("szItemID").First();
var val4 = (string)doc.Descendants("Set").Elements("lMerchandiseStructureID").First();
var val5 = (string)doc.Descendants("Set").Elements("szName").First();
var val6 = (string)doc.Descendants("Set").Elements("lRetailStoreID").First();
var val7 = (string)doc.Descendants("Set").Elements("bIsContract").First();
dataToBeWritten.Append(val3);
dataToBeWritten.Append(",");
dataToBeWritten.Append(val4);
dataToBeWritten.Append(",");
dataToBeWritten.Append(val5);
dataToBeWritten.Append(",");
dataToBeWritten.Append(val6);
dataToBeWritten.Append(",");
dataToBeWritten.Append(val7);
dataToBeWritten.Append(",");
dataToBeWritten.Append(Environment.NewLine);
}
Console.WriteLine(dataToBeWritten.ToString());
Console.ReadLine();
var testpath = #"D:\\Lutchmee2.csv";
File.WriteAllText(testpath, dataToBeWritten.ToString());

Your XElement is UpdateDB, so from that context there is no child UpdateDB. You'd have to amend your query to:
/Transaction/Insert/Set/szItemID
That said, it's unclear why you're loading the document into the DOM, converting it to a string and than parsing to an XElement. Just load into an XDocument and use your original query:
var doc = XDocument.Load(#"D:\xml_1.xml");
var val = (string) doc.XPathSelectElement("/UpdateDB/Transaction/Insert/Set/szItemID");
Or better still, use LINQ to XML as it was intended:
var val = (string) doc.Descendants("Set").Elements("szItemID").First()

Related

Getting innertext of XML node

When i try M Adeel Khalid kode i get nothing, and trying others i get errors. i miss something, but i cant se it. My code look like this. but i get an error on Descendants, Saying "xmlDocument does not contain a definition for descendants" As you can probably see, I'm pretty new to this, so bear with me.
protected void btnRetVare_Click(object sender, EventArgs e)
{
fldRetVare.Visible = true;
try
{
functions func = new functions();
bool exists = func.checForMatch(txtRetVare.Text);
string myNumber = txtRetVare.Text;
if (Page.IsValid)
{
if (!exists)
{
txtRetVare.Text= "Varenummer findes ikke";
}
else
{
XmlDocument xmldoc = new XmlDocument();
//xmldoc.Load(Server.MapPath(map));
xmldoc.LoadXml(Server.MapPath(map));
//var Varenummer2055component = xmldoc.SelectNodes("s/Reservedele/Component[Varenummer/text()='"+txtRetVare+"']/Remarks");
//if (Varenummer2055component.Count == 1)
//{
// var remarks = Varenummer2055component[0].InnerText;
// txtRetBemærkninger.Text = remarks.ToString();
//}
string remarks = (from xml2 in xmldoc.Descendants("Component")
where xml2.Element("Varenummer").Value == txtRetVare.Text
select xml2.Element("Remarks")).FirstOrDefault().Value;
txtRetBemærkninger.Text = remarks;
}
}
You can get it this way.
XDocument xdoc = XDocument.Load(XmlPath);
string remarks = (from xml2 in xdoc.Descendants("Component")
where xml2.Element("Varenummer").Value == "2055"
select xml2.Element("Remarks")).FirstOrDefault().Value;
I've tested this code.
Hope it helps.
Use XPath to select the correct node:
XmlDocument xml = new XmlDocument();
xml.LoadXml(#"
<Reservedele>
<Component>
<Type>Elektronik</Type>
<Art>Wheel</Art>
<Remarks>erter</Remarks>
<Varenummer>2055</Varenummer>
<OprettetAf>jg</OprettetAf>
<Date>26. januar 2017</Date>
</Component>
<Component>
<Type>Forbrugsvarer</Type>
<Art>Bulb</Art>
<Remarks>dfdh</Remarks>
<Varenummer>2055074</Varenummer>
<OprettetAf>jg</OprettetAf>
<Date>27. januar 2017</Date>
</Component>
</Reservedele>");
var Varenummer2055component = xml.SelectNodes("s/Reservedele/Component[Varenummer/text()='2055']/Remarks");
if (Varenummer2055component.Count == 1)
{
var remarks = Varenummer2055component[0].InnerText;
}
I think extension method First of LINQ to XML will be simple enough and fill requirements of your questions.
var document = XDocument.Load(pathTopXmlFile);
var remark =
document.Descendants("Component")
.First(component => component.Element("Varenummer").Value.Equals("2055"))
.Element("Remarks")
.Value;
First method will throw exception if xml doesn't contain element with Varenummer = 2055
In case where there is possibility that given number doesn't exists in the xml file you can use FirstOrDefault extension method and add checking for null
var document = XDocument.Load(pathTopXmlFile);
var component =
document.Descendants("Component")
.FirstOrDefault(comp => comp.Element("Varenummer").Value.Equals("2055"));
var remark = component != null ? component.Element("Remarks").Value : null;
For saving new value you can use same "approach" and after setting new value save it to the same file
var document = XDocument.Load(pathTopXmlFile);
var component =
document.Descendants("Component")
.FirstOrDefault(comp => comp.Element("Varenummer").Value.Equals("2055"));
component.Element("Remarks").Value = newValueFromTextBox;
document.Save(pathTopXmlFile);
One more approach, which will be overkill in your particular case, but can be useful if you use other values of xml. This approach is serialization.
You can create class which represent data of your xml file and then just use serialization for loading and saving data to the file. Examples of XML Serialization

Save the same element from XML file as an array C#

it could be a silly question, but i want ta ask, how can I save the same element from an .XML file with different content as an array.
Example XML:
<ithem>
<description>description1</description>
<description>description2</description>
<description>description3</description>
</ithem>
then string [] descriptions will be
descriptions[0] = "description1";
descriptions[1] = "description2";
descriptions[2] = "description3";
Please help!
Using LINQ to XML it would be:
XElement root = XElement.Load(xmlFile);
string[] descriptions = root.Descendants("description").Select(e => e.Value).ToArray();
or
string[] descriptions = root.Element("ithem").Elements("description").Select(e => e.Value).ToArray();
Use XmlDocument to parse the XML :
var map = new XmlDocument();
map.Load("path_to_xml_file"); // you can also load it directly from a string
var descriptions = new List<string>();
var nodes = map.DocumentElement.SelectNodes("ithem/description");
foreach (XmlNode node in nodes)
{
var description = Convert.ToString(node.Value);
descriptions.Add(description);
}
And you get it as an array from:
descriptions.ToArray();

Read XML with schema without xsd file

I received a complex XML file this week and it is schema based, but i didn't received any xsd file and i need to read each node of this one.
XML sample bellow:
<xc:XmlTest xmlns:xc="XmlTest" xmlns:mp="bs.TestParameters" xmlns:rt="bs.TestParameters.Parameter1" xmlns:rtcu="bs.TestParameters.Parameter1.Var">
<xc:XmlTestArea xc:value="TestParameters">
<mp:Name xc:Value="raddesso" xmlns:mp="bs.TestParameters">
<mp:Date xc:Value="20130215">
<rt:RunTest xmlns:rt="bs.TestParameters.Parameter1">
<rtcu:Var xmlns:rtcu="bs.TestParameters.Parameter1.Var">
<mp:FinalValue>1234</mp:FinalValue>
</rtcu:Var>
</rt:RunTest>
</mp:Date>
<mp:Date xc:Value="20130216">
<rt:RunTest xmlns:rt="bs.TestParameters.Parameter1">
<rtcu:Var xmlns:rtcu="bs.TestParameters.Parameter1.Var">
<mp:FinalValue>23234</mp:FinalValue>
</rtcu:Var>
</rt:RunTest>
</mp:Date>
</mp:Name>
</xc:XmlTestArea>
</xc:XmlTest>
This is only a sample of the true file, using fake data.
Is there any way to do a foreach on this nodes to find the FinalValue from each date?
You don't need a schema to read a file. The schema is only used to validate the file (to check integrity). But this step is optional.
To read the XML file. I suggest to use Linq-to-XML.
const string mpNamespace = "bs.TestParameters";
XDocument xDocument = XDocument.Load("C:/Path to the file.xml");
List<string> finalValues = (from dateNode in xDocument.Descendants(XName.Get("Date", mpNamespace)) // Gets all Date nodes in the document
from finalValueNode in dateNode.Descendants(XName.Get("FinalValue", mpNamespace)) // Gets all FinalValue nodes in the Date nodes
select finalValueNode.Value // Gets the value of each FinalValue node
).ToList();
Update
To return the Date and the FinalValue you can use anonymous types:
const string mpNamespace = "bs.TestParameters";
const string xcNamespace = "XmlTest";
XDocument xDocument = XDocument.Load("C:/Path to the file.xml");
var finalValues = (from dateNode in xDocument.Descendants(XName.Get("Date", mpNamespace)) // Gets all Date nodes in the document
from finalValueNode in dateNode.Descendants(XName.Get("FinalValue", mpNamespace)) // Gets all FinalValue nodes in the Date nodes
select new // Creates an instance of an anonymous type with Date and FinalValue
{
Date = dateNode.Attribute(XName.Get("Value", xcNamespace)).Value,
FinalValue = finalValueNode.Value // Gets the value of each FinalValue node
}
).ToList();
XmlDocument doc = new XmlDocument();
doc.Load("path to xml file");
XmlNodeList finalValues = doc.GetElementByTagName("FinalValue");
finalValues will be a list of node that has the tag name "FinalValue", you can then read the inner text and story in a list.
List<string> values = new List<string>();
foreach(XmlNode node in finalValues)
values.Add(node.InnerText);

Get certain xml node and save the value

Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);

How to modify an xml attribute's value?

How can i modify the value of an attribute within an xml loaded using Loadxml()?
I'm trying to update the xml string stored in my db. For that, i used the following code:
XmlDocument doc = new XmlDocument();
doc.LoadXml(project.ProjectData);
XmlNodeList pNodes = doc.SelectNodes("project");
foreach (XmlNode pNode in pNodes)
{
XmlAttribute lPDAttribute = pNode.Attributes["lastPubDate"];
if (lPDAttribute != null)
{
string currentValue = lPDAttribute.Value;
if (string.IsNullOrEmpty(currentValue))
{
lPDAttribute.Value = project.PublishDate.ToString();
}
}
}
What should i do to save the updated attribute within my current xml? Please help.
I think you should add the below code line
project.ProjectData = doc.InnerXml
you can store doc.InnerXml as a string in your db

Categories

Resources