Load XML file into SQL Server tables using C# - c#

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

Related

Extracting nested nodes from xml file c#

I have this xml file:
<table head="Film">
<row>
<id>USD</id><jan>Jan</jan><feb>Feb</feb><mar>Mar</mar><apr>Apr</apr><maj>May</maj><jun>Jun</jun><jul>Jul</jul><aug>Aug</aug><sep>Sep</sep><okt>Oct</okt><nov>Nov</nov><dec>Dec</dec><sum>Year</sum>
</row>
<row>
<id>2018</id><jan>7629</jan><feb>6433</feb><mar>5573</mar><apr>3676</apr><maj>2545</maj><jun>2542</jun><jul>266</jul><aug>276</aug><sep>2690</sep><okt>371</okt><nov>5446</nov><dec>754</dec><sum>52731</sum>
</row>
I'm trying to extract the individual values for every month.
I've tried
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("model.xml");
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("table");
foreach (XmlNode node in nodeList) // for each <testcase> node
{
Console.WriteLine(node["row"].InnerText);
}
This gives an exception because node["row"] is empty.
Any ideas?
Firstly your XML is not valid. You need to have a </table> on there.
//In this example GetXml() just returns your XML
var doc = XDocument.Parse(GetXml());
var rows = doc.Descendants("table").Elements("row").ToList();
foreach(var element in rows[1].Elements()){
Console.WriteLine(element?.Value);
}
Now this is just a basic example based of your XML. You would likely want it to be more robust. You will notice I am showing you this with LINQ, I feel it's more readable than XmlDocument.
You need to loop through the child nodes to get your desired result as follow:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("model.xml");
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("table");
foreach (XmlNode node in nodeList) // for each <testcase> node
{
foreach (XmlNode row in node.ChildNodes)
{
foreach (XmlNode mon in row.ChildNodes)
{
}
}
}

Adding info to a xml file

I have a XML file which contains about 850 XML nodes. Like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
........ 849 more
And I want to add a new Childnode inside each and every Node. So I end up like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
<Description>TestDescription</Description>
</NameValueItem>
........ 849 more
I've tried the following:
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNodeList nodes = doc.GetElementsByTagName("NameValueItem");
Which gives me all of the nodes, but from here am stuck(guess I need to iterate over all of the nodes and append to each and every) Any examples?
You need something along the lines of this example below. On each of your nodes, you need to create a new element to add to it. I assume you will be getting different values for the InnerText property, but I just used your example.
foreach (var rootNode in nodes)
{
XmlElement element = doc.CreateElement("Description");
element.InnerText = "TestDescription";
root.AppendChild(element);
}
You should just be able to use a foreach loop over your XmlNodeList and insert the node into each XmlNode:
foreach(XmlNode node in nodes)
{
node.AppendChild(new XmlNode()
{
Name = "Description",
Value = [value to insert]
});
}
This can also be done with XDocument using LINQ to XML as such:
XDocument doc = XDocument.Load(xmlDoc);
var updated = doc.Elements("NameValueItem").Select(n => n.Add(new XElement() { Name = "Description", Value = [newvalue]}));
doc.ReplaceWith(updated);
If you don't want to parse XML using proper classes (i.e. XDocument), you can use Regex to find a place to insert your tag and insert it:
string s = #"<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>";
string newTag = "<Description>TestDescription</Description>";
string result = Regex.Replace(s, #"(?<=</Code>)", Environment.NewLine + newTag);
but the best solution is Linq2XML (it's much better, than simple XmlDocument, that is deprecated at now).
string s = #"<root>
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
<NameValueItem>
<Text>Test2</Text>
<Code>Test2</Code>
</NameValueItem>
</root>";
var doc = XDocument.Load(new StringReader(s));
var elms = doc.Descendants("NameValueItem");
foreach (var element in elms)
{
element.Add(new XElement("Description", "TestDescription"));
}
var text = new StringWriter();
doc.Save(text);
Console.WriteLine(text);

How to get the value for multiple subnode in xml?

Xml code:
<Report>
<ChartData>
<ListName>area</ListName>
<ViewName>Selecte List</ViewName>
<YAxisFields>
<YAxisField>
<Name>Scheduled Start Date/Time</Name>
<DataType>DateTime</DataType>
<Category>Year</Category>
</YAxisField>
</YAxisFields>
<XAxisFields>
<XAxisField>
<Name>Release Type</Name>
<DataType>String</DataType>
<Category>
</Category>
</XAxisField>
</XAxisFields>
</ChartConfig>
</Report>
I got the value for the subnode listname and viewname by using the
below code,
XmlDocument doc = new XmlDocument();
doc.Load("XmlFileName");
XmlNodeList node = doc.SelectNodes("Report/ChartData");
foreach (XmlNode xn in node)
{ xn["ListName"].InnerXml = chartname;
xn["ViewName"].InnerXml = SelectedList;
**xn["YAxisFields/YAxisField"].InnerXml = yaxisfield; //not working, need to get the value for this xml node,need help in this line dono how to proceed**
doc.Save("XmlFilename");
}
First i have tried with code like this instead of above code,in this
i need to create number of objects in order get the value for each
node so i tried by creating object for xmlnodelist then i used
foreach loop to get the value for each node but in this couldnt get
the value for YAxisFields/YAxisField because it also has parent node
as YAxisFields and subnode as YAxisField so there is only way to
create number of objects for xmlnode or is there any other way to do
this?
XmlDocument doc = new XmlDocument();
doc.Load("XmlFileName");
XmlNode Listnode = doc.SelectSingleNode("Report/ChartData/ListName");
XmlNode Viewnode = doc.SelectSingleNode("Report/ChartData/ViewName");
if (Listnode != null)
{
Listnode.InnerXml = chartname;
Viewnode.InnerXml = SelectedList; ;
doc.Save("XmlFileName");
Use Linq to XML XDocument, like this:
doc.Root.Descendants("ChartData").ToList().ForEach(node =>
{
node.Element("ListName").Value = chartname;
node.Element("ViewName").Value = SelectedList;
});

Read a XML (from a string) and get some fields - Problems reading XML

I have this XML (stored in a C# string called myXML)
<?xml version="1.0" encoding="utf-16"?>
<myDataz xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<listS>
<sog>
<field1>123</field1>
<field2>a</field2>
<field3>b</field3>
</sog>
<sog>
<field1>456</field1>
<field2>c</field2>
<field3>d</field3>
</sog>
</listS>
</myDataz>
and I'd like to browse all <sog> elements. For each of them, I'd like to print the child <field1>.
So this is my code :
XmlDocument xmlDoc = new XmlDocument();
string myXML = "<?xml version=\"1.0\" encoding=\"utf-16\"?><myDataz xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><listS><sog><field1>123</field1><field2>a</field2><field3>b</field3></sog><sog><field1>456</field1><field2>c</field2><field3>d</field3></sog></listS></myDataz>"
xmlDoc.Load(myXML);
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("listS");
foreach (XmlNode childrenNode in parentNode)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("//field1").Value);
}
but seems I can't read a string as XML? I get System.ArgumentException
You should use LoadXml method, not Load:
xmlDoc.LoadXml(myXML);
Load method is trying to load xml from a file and LoadXml from a string. You could also use XPath:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
string xpath = "myDataz/listS/sog";
var nodes = xmlDoc.SelectNodes(xpath);
foreach (XmlNode childrenNode in nodes)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("//field1").Value);
}
Use Linq-XML,
XDocument doc = XDocument.Load(file);
var result = from ele in doc.Descendants("sog")
select new
{
field1 = (string)ele.Element("field1")
};
foreach (var t in result)
{
HttpContext.Current.Response.Write(t.field1);
}
OR : Get the node list of <sog> tag.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(myXML);
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("sog");
foreach (XmlNode childrenNode in parentNode)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("field1").InnerText);
}
The other answers are several years old (and do not work for Windows Phone 8.1) so I figured I'd drop in another option. I used this to parse an RSS response for a Windows Phone app:
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(xml_string);
Or use the XmlSerializer class.
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(new StringReader(yourXmlString));
I used the System.Xml.Linq.XElement for the purpose. Just check code below for reading the value of first child node of the xml(not the root node).
string textXml = "<xmlroot><firstchild>value of first child</firstchild>........</xmlroot>";
XElement xmlroot = XElement.Parse(textXml);
string firstNodeContent = ((System.Xml.Linq.XElement)(xmlroot.FirstNode)).Value;

reading xml by tag and writing

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);
}

Categories

Resources