I am working on a programm with C# and a XML-File. I want to read the values of the xml-nodes but I get an issue with that. In the second part, where I am trying to get the content, it only does one loop and not three. The first values are correct. I don't know why it only makes the first loop. I hope someone can help me.
My XML-File:
<?xml version="1.0" encoding="utf-8"?>
<lagerverwaltung>
<article>
<inventory id="1">
</inventory>
<orders>
<order id="1">
<id>1</id>
<idposition>1</idposition>
<content>
<idarticle amount="4">2</idarticle>
<idarticle amount="3">3</idarticle>
<idarticle amount="2">1</idarticle>
</content>
<idcustomer>2</idcustomer>
<orderdate>05.01.2018 15:10:44</orderdate>
<paydate>05.02.2018</paydate>
<mwst>7.7</mwst>
<total>1781.358</total>
</order>
</orders>
</article>
</lagerverwaltung>
My C#-Code:
List<Order> orderList = new List<Order>();
XmlDocument xml = new XmlDocument();
xml.Load(xmlFilePath);
XmlNodeList xnList = xml.SelectNodes("/lagerverwaltung/article/orders/order");
foreach (XmlNode xn in xnList)
{
// Is working
string id = xn["id"].InnerText;
string bestellPositionId = xn["idposition"].InnerText;
string kundeId = xn["idcustomer"].InnerText;
string bestelldatum = xn["orderdate"].InnerText;
string rechnungsDatum = xn["paydate"].InnerText;
string mwst = xn["mwst"].InnerText;
string rechnungsTotal = xn["total"].InnerText;
XmlNodeList xnInhalt = xml.SelectNodes("/lagerverwaltung/article/orders/order[#id='" + id + "']/content");
Dictionary<string, string> content= new Dictionary<string, string>();
foreach (XmlNode xmlNode in xnInhalt) // Does only one loop
{
string articleid = xmlNode["idarticle"].InnerText;
string amount = xmlNode["idarticle"].GetAttribute("amount");
content.Add(articleid, amount);
}
}
There is a single content node, use content/idarticle to get the inner collection:
XmlNodeList xnInhalt = xml.SelectNodes("/lagerverwaltung/article/orders/order[#id='" + id
+ "']/content/idarticle");
You would then modify the following code because xmlNode now refers to an idarticle. For example,
string articleid = xmlNode.InnerText;
Related
I have complex XML file that export from old program in VB6, now I must write a program in C# to load this XML file into 2 tables. Here is the XML file structure:
<?xml version="1.0" encoding="SHIFT-JIS" standalone="yes"?>
<AdminFile>
<PO_No></PO_No>
<Database>
<PO>
<Table_PO_Master>
<DATA>
<PO_No></PO_No>
<PO_Date></PO_Date>
</DATA>
</Table_PO_Master>
<Table_PO_Details>
<DATA>
<PO_No></PO_No>
<GOODS_CD></GOODS_CD>
<QTY></QTY>
</DATA>
</Table_PO_Details>
</PO>
</Database>
</AdminFile>
I need to load this XML into 2 SQL Server tables that have the structure as below:
Table_PO_Master(Id,PO_No,PO_Date)
Table_PO_Details(PO_No,GOODS_CD,QTY)
I googled and found this code but do not know to to apply it in my case.
string myXMLfile = "D:\\MyXML.xml";
XmlTextReader textReader = new XmlTextReader(myXMLfile);
XmlDocument doc = new XmlDocument();
doc.Load(myXMLfile);
XmlNodeList List = doc.GetElementsByTagName("RWResponse");
foreach (XmlNode node in List)
{
XmlNode Element = (XmlNode)node;
foreach (XmlNode node1 in Element)
{
XmlNode Element1 = (XmlNode)node1;
foreach (XmlNode node2 in Element1)
{
XmlNode Element2 = (XmlNode)node2;
foreach (XmlNode node3 in Element2)
{
XmlNode Element3 = (XmlNode)node3;
if (Element3.Name.ToUpper() != "HEADER")
{
if (!Element3.OuterXml.ToString().Contains("ROW type=\"subtotal\""))
{
if (!Element3.OuterXml.ToString().Contains("ROW type=\"total\""))
{
DataRow dr = ret_XML_Data_in_DataTable.NewRow();
foreach (XmlNode node4 in Element3)
{
XmlElement Element4 = (XmlElement)node4;
}
}
}
}
}
}
}
}
}
If you want to save data by SP than you need not to load xml in your c# application,
Pass your xml as a store procedure parameter usingo ado.net,
After you can extract xml and insert the data
so your SP is like,
CREATE PROCEDURE [dbo].[InsertData]
#xml XML
AS
BEGIN
INSERT INTO Table_PO_Master
SELECT
PO_Master.value('(PO_No/text())[1]','VARCHAR(100)') AS PO_No, --TAG
PO_Master.value('(PO_Date/text())[1]','VARCHAR(100)') AS PO_Date --TAG
FROM
#xml.nodes('/AdminFile/Database/PO/Table_PO_Master/Data')AS TEMPTABLE(PO_Master)
INSERT INTO Table_PO_Details
SELECT
PO_Master.value('(PO_No/text())[1]','VARCHAR(100)') AS PO_No, --TAG
PO_Master.value('(GOODS_CD/text())[1]','VARCHAR(100)') AS GOODS_CD --TAG
PO_Master.value('(QTY/text())[1]','int') AS QTY --TAG
FROM
#xml.nodes('/AdminFile/Database/PO/Table_PO_Details/Data')AS TEMPTABLE(PO_Details)
End
You can also use XDocument:
var doc = XDocument.Parse(xml);
foreach (XElement xe in doc.Descendants("Table_PO_Master"))
{
var PO_No = xe.Element("DATA").Element("PO_No").Value;
var PO_Date = xe.Element("DATA").Element("PO_Date").Value;
SaveIntoMaster(PO_No, PO_Date);
}
and do the same for Table_PO_Details
I have the below XML, and I am trying to write values to a CSV file. I am however not sure how to proceed further, with everything I've tried throwing errors. The below returns:"Expression must evaluate to a node-set". Any assistance is appreciated.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Body>
<RESULT>
<SUCCESS>TRUE</SUCCESS>
<Mailing>
<MailingId>9285984</MailingId>
<ReportId>362040252</ReportId>
<ScheduledTS>2014-08-22 11:44:33.0</ScheduledTS>
<MailingName>305_ENDS</MailingName>
</Mailing>
<Mailing>
<MailingId>9278770</MailingId>
<ReportId>361956135</ReportId>
<ScheduledTS>2014-08-22 09:15:00.0</ScheduledTS>
<MailingName>141_TSI</MailingName>
<Visibility>Shared</Visibility>
</Mailing>
<Mailing>
<MailingId>9286460</MailingId>
<ReportId>362043622</ReportId>
<ScheduledTS>2014-08-22 12:57:30.0</ScheduledTS>
<MailingName>301_BRANDREP</MailingName>
</Mailing>
</RESULT>
</Body>
</Envelope>
C#:
xpathDoc = HttpHelper.HttpStream(xmlReq, sessionid);
XPathNavigator nav = xpathDoc.CreateNavigator();
XPathNodeIterator xmlIterator = nav.Select("/Envelope/Body/RESULT/");
var csv = new StringBuilder();
filePath = "C:\Campaigns.csv";
foreach (XPathNavigator node in xmlIterator)
{
string MailingId = node.SelectSingleNode("MailingId").Value;
string ReportId = node.SelectSingleNode("ReportId").Value;
string ScheduledTS = node.SelectSingleNode("ScheduledTS").Value;
string MailingName = node.SelectSingleNode("MailingName").Value;
string newLine = string.Format("{0},{1},{2},{3},{4}", MailingId, ReportId, ScheduledTS, MailingName, Environment.NewLine);
csv.Append(newLine);
}
File.WriteAllText(filePath, csv.ToString());
Well, you can try following approach:
foreach (XPathNavigator node in nav.Select("/Envelope/Body/RESULT/Mailing"))
{
string MailingId = node.SelectSingleNode("./MailingId").Value;
// and so on
Note: it should be exactly Mailing not RESULT as in your query, and should not ends with /
Change XPathNavigator node in nav.Select("/Envelope/Body/RESULT/") to XPathNavigator node in nav.Select("/Envelope/Body/RESULT/Mailing") and then use e.g. string MailingId = node.SelectSingleNode("MailingId").Value;.
I don't how to extract the values from XML document, and am looking for some help as I'm new to C#
I am using XmlDocument and then XmlNodeList for fetching the particular XML document
Here is my code
XmlNodeList XMLList = doc.SelectNodes("/response/result/doc");
And my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<result>
<doc>
<long name="LoadID">494</long>
<long name="EventID">5557</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
<doc>
<long name="LoadID">774</long>
<long name="EventID">5558</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
</result>
</response>
In this i have to fetch every the XMLData data that is under every doc tag and i have to fetch last doc tag EventID.
var xml = XDocument.Parse(xmlString);
var docs = xml.Root.Elements("doc");
var lastDocEventID = docs.Last()
.Elements("long")
.First(l => (string)l.Attribute("name") == "EventID")
.Value;
Console.WriteLine ("Last doc EventId: " +lastDocEventID);
foreach (var doc in docs)
{
Console.WriteLine (doc.Element("str").Element("TransactionDate").Value);
}
prints:
Last doc EventId: 5558
2014-05-28T14:17:31.2186777-06:00
2014-05-28T14:17:31.2186777-06:00
You can use two XPath expressions to select the nodes you want. To answer each part of your question in turn:
To select all of the XMLData nodes:
XmlNodeList XMLList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
To select the last EventId:
XmlNode lastEventIdNode =
doc.SelectSingleNode("/response/result/doc[position() =
last()]/long[#name='EventID']");
If not all doc nodes are guaranteed to have an event id child node, then you can simply:
XmlNodeList eventIdNodes =
doc.SelectNodes("/response/result/doc[long[#name='EventID']]");
XmlNode lastNode = eventIdNodes[eventIdNodes.Count - 1];
That should give you what you've asked for.
Update;
If you want the XML data inside each strXml element, you can use the InnerXml property:
XmlNodeList xmlList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
foreach(XmlNode xmlStrNode in xmlList)
{
string xmlInner = xmlStrNode.InnerXml;
}
There's one result tag short in your xml.
Try using this. It's cleaner too imho
XmlNodeList docs = doc.SelectSingleNode("response").SelectSingleNode("result").SelectNodes("doc");
Then you can use a combination of SelectSingleNode, InnerText, Value to get the data from each XmlNode in your list.
For example if you want the EventID from the first doc tag:
int eventID = int.Parse(docs[0].SelectSingleNode("long[#name='EventID']").InnerText);
reading xml by tag in a foreach loop
example xml:
<users>
<user>
<id>12345567</id>
<name>Ronsna Stedinberg</name>
</user>
<user>
<id>12345568</id>
<name>Sonsna Dtedinberg</name>
</user>
</users>
now i would like to save a tag to a new file with all its sub tags
This is how you would loop the user nodes
string xml = #"<users><user><id>12345567</id><name>Ronsna Stedinberg</name></user><user><id>12345568</id><name>Sonsna Dtedinberg</name></user></users>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList nodeList = doc.SelectNodes("//users/user");
foreach (XmlNode node in nodeList)
{
string id = node.SelectSingleNode("id").InnerText;
string name = node.SelectSingleNode("name").InnerText;
}
A Linq to XML approach:
// Assuming your xml is named data.xml
XDocument xml = XDocument.Load("data.xml");
var tags = from x in xml.Descendants("user")
select new
{
id = x.Element("id").Value,
name = x.Element("name").Value
};
foreach (var tag in tags)
{
Console.WriteLine(tag.id);
Console.WriteLine(tag.name);
}
I do not need to edit any XML-file or anything, this is only for reading and parsing.
I want to be able to handle the XML-document as a dictionary, like: username = doc["username"];, but I can't find out how to "convert" the document. I've also encountered the problem with duplicate key-names, but that could be easlily avoided by appending each value with 1, 2 etc; making it easy to for-loop through too.
Is this possible? To treat the (parsed) XML-document as a dictionary?
Answer to Mehrdad:
It varies from time to time, it depends on the request from the user. If the user requests x, then it will be:
<xml>
<test>foo</test>
<bar>123</bar>
<username>foobar</username>
</xml>
But if he requests y, it will be like
<xml>
<ammount>1000</ammount>
<mail>...#...</mail>
<username>foobar</username>
</xml>
The best would be if this:
<xml>
<mengde>100</mengde>
<type>3</type>
<mail>foo</mail>
<crypt>bar</crypt>
<username>bar</username>
</xml>"
Could be parsed and then accessed as doc["mengde"] etc.
You could use linq to xml to do what you want (if I understand what you want)
string data = "<data><test>foo</test><test>foobbbbb</test><bar>123</bar><username>foobar</username></data>";
XDocument doc = XDocument.Parse(data);
Dictionary<string, string> dataDictionary = new Dictionary<string, string>();
foreach (XElement element in doc.Descendants().Where(p => p.HasElements == false)) {
int keyInt = 0;
string keyName = element.Name.LocalName;
while (dataDictionary.ContainsKey(keyName)) {
keyName = element.Name.LocalName + "_" + keyInt++;
}
dataDictionary.Add(keyName, element.Value);
}
XML Data
<?xml version="1.0" encoding="UTF-8"?>
<data>
<resource key="123">foo</resource>
<resource key="456">bar</resource>
<resource key="789">bar</resource>
</data>
Conversion Code
string s = "<data><resource key=\"123\">foo</resource><resource key=\"456\">bar</resource><resource key=\"789\">bar</resource></data>";
XmlDocument xml = new XmlDocument();
xml.LoadXml(s);
XmlNodeList resources = xml.SelectNodes("data/resource");
SortedDictionary<string,string> dictionary = new SortedDictionary<string,string>();
foreach (XmlNode node in resources){
dictionary.Add(node.Attributes["key"].Value, node.InnerText);
}
This question was asked before here and so you can find the all answers in this link :
convert xml to sorted dictionary
Hope it helps.
Your question's really not very clear, but I think this does what you want:
XmlDocument doc = new XmlDocument();
doc.LoadXml(#"<xml>
<mengde>100</mengde>
<type>2</type>
<foo>bar</foo>
</xml>");
Dictionary<string, string> d = new Dictionary<string, string>();
foreach (XmlNode n in doc.SelectNodes("/xml/*")
{
d[n.Name] = n.Value;
}
This isn't exactly what you are looking for, but may be of interest: http://blogs.msdn.com/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introducing-the-expandoobject.aspx