But it gives me exception like "There are multiple root elements. Line 3, position 2." on the line reader.MoveToContent();
Below is the sample code that i use
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace sample
{
class Program
{
static void Main(string[] args)
{
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader("C:\\Users\\ADMIN\\Pictures\\test.xml");
string contents = "";
while (reader.Read())
{
reader.MoveToContent();
if (reader.NodeType == System.Xml.XmlNodeType.Element)
contents += "<" + reader.Name + ">\n";
if (reader.NodeType == System.Xml.XmlNodeType.Text)
contents += reader.Value + "\n";
}
Console.Write(contents);
Console.ReadLine();
}
}
}
please help.
You are trying to parse an XML document, that, stand-alone, isn't valid XML. Therefore, you need to tell it that it is only a fragment. This will prevent it from throwing an error about multiple root elements.
You can do this by replacing the line
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader("C:\\Users\\ADMIN\\Pictures\\test.xml");
with:
var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
var reader = System.Xml.XmlTextReader.Create("C:\\Users\\ADMIN\\Pictures\\test.xml", settings);
Related
my code converts an inventory xml file to a csv file. It works as intended. Now I want to add headers, the issue is, when I add the headers into my code, the list of of items disappear.
The desired output is, to add a total of 6 headers and finally, add the corresponding values to each header. The image below, demonstrates what the expected output should be.
After I added, string csvHeader, the headers get created but the corresponding values are not showing. As shown below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace myApp{
class WriteToCSVFile{
static void Main(String[] args){
// Open file and rename it.
//string name;
string xml = File.ReadAllText("C:\\bartact_inventory.xml");
XDocument Xdoc = XDocument.Parse(xml);
string csvHeader = "Application/Fitment" + "," + "Part #" + "," + "Item Description" +
"," + "Vendor" + "," + "QOH" + "," + "Unit Of Measure";
XElement xeQBXML = Xdoc.Element("QBXML");
XElement xeQBXMLMsgsRs = xeQBXML.Element("QBXMLMsgsRs");
XElement XDEGeneralSummaryReportQueryRs =
xeQBXMLMsgsRs.Element("GeneralSummaryReportQueryRs");
XElement xeReportRet = XDEGeneralSummaryReportQueryRs.Element("ReportRet");
XElement xeReportData = xeReportRet.Element("ReportData");
List<XElement> xeDataRows = xeReportData.Elements("DataRow").ToList();
List<string> csvRows = new List<string>();
for (int rowdata = 0; rowdata < xeDataRows.Count; rowdata++)
{
string csvRow = "";
//string csvHeader = "";
XElement xeData = xeDataRows[rowdata];
XElement RowData = xeData.Elements("RowData").ToList().ElementAt(0);
//Returns Values from RowData which includes year or category and item part number
string[] partIDs = RowData.Attribute("value").Value.Split(":");
if(partIDs.Length == 2)
{
csvRow = partIDs[0] + "," + partIDs[1] + ",";
//Returns all ColData
List<XElement> xeColData = xeData.Elements("ColData").ToList();
for (int colData = 0; colData < xeColData.Count; colData++)
{
XElement partAttributes = xeColData.ElementAt(colData);
string colID = partAttributes.Attribute("colID").Value;
string value = partAttributes.Attribute("value").Value;
csvRow += value + ",";
}
// add cr
//File.WriteAllText("C:\\bartact_inventory.csv",);
csvRows.Add(csvRow);
}
}
File.WriteAllText("C:\\bartact_inventoy1.csv",string.Join("\n",csvHeader,"\n",csvRows));
}
}
}
I'd suggest a couple of changes. First, instead of adding the header when you write the file, add it to your csvRows List before the loop that adds the data:
csvRows.Add(csvHeader);
Second, I wouldn't use the File.WriteAllText and a Join but rather use File.WriteAllLines which lets you skip the join.
File.WriteAllText("C:\\bartact_inventory1.csv", csvRows);
Which at least in my test does what you want. There is also a decent library (ChoETL) that handles writing CSV files along with data conversions etc. that might be worth looking at.
Instead of:
string.Join("\n",csvHeader,"\n",csvRows)
Try:
string.Join("\n",csvHeader, string.Join("\n",csvRows.ToArray()))
Would recommend to use string builder for all places where we have new line or carriage return operations. For instance instead of doing Join("\n") using new line symbol we can do the following stuff
var sb = new StringBuilder();
sb.AppendLine(csvHeader);
foreach (var csvRow in csvRows)
{
sb.AppendLine(csvRow);
}
File.WriteAllText("bartact_inventoy1.csv", sb.ToString());
Here the catch, sb.AppendLine will produce proper output with not just new line symbol but also with carriage return (CR)
PS: seems in your example you also missed
string colID = partAttributes.Attribute("colID").Value
to be added to output
I have a text file contains 500+ xmlelements like the following:
<Data a="a" b="b" c="c" d="d"><Date runDt="01-01-1900" /></Data>
Can someone please show me how to read/load it so I can retrieve certain attributes/elements? And once I manipulate the data, write it back to a new text file (and needs to be a .txt file without any xml headers).
Thanks :)
Easiest way is to use:
using System.Xml;
XmlDocument xml = new XmlDocument ();
xml.InnerXml = #"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>";
Console.WriteLine (xml.ChildNodes [0].Attributes [0].InnerText);
Will print
a
Using XmlDocument is very easy, just check its fields, variables and methods.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n";
//xml can only contain one root tag. Need to wrap xml in root tag if one is missing
input = string.Format("<Root>{0}</Root>", input);
XDocument doc = XDocument.Parse(input);
// if loading from file
//string input = File.ReadAllText(filename);
//input = string.Format("<Root>{0}</Root>", input);
//XDocument doc = XDocument.Load(filename);
var results = doc.Descendants("Data").Select(x => new
{
a = x.Attribute("a").Value,
b = x.Attribute("b").Value,
c = x.Attribute("c").Value,
d = x.Attribute("d").Value,
date = DateTime.Parse(x.Element("Date").Attribute("runDt").Value)
}).ToList();
}
}
}
I have used the following code before but my xml is different this time:
protected string ReturnXmlValue(XmlDocument myXDoc, string field)
{
var retval = string.Empty;
try
{
var node = myXDoc.GetElementsByTagName(field);
if (node.Count > 0)
{
var xmlNode = node.Item(0);
if (xmlNode != null)
{
retval = xmlNode.InnerText;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
throw;
}
return retval;
}
Here is an example of my xml file dummied down a bit:
<RichDBDS>
<TrxDetailCard>
<TRX_HD_Key>18683435</TRX_HD_Key>
<Date_DT>2015-10-22T21:32:00.233+00:00</Date_DT>
<TRX_Card_Key>15263569</TRX_Card_Key>
<Total_Amt_MN>22.0000</Total_Amt_MN>
<Result_CH>0 </Result_CH>
<Result_Txt_VC>APPROVED</Result_Txt_VC>
<Approval_Code_CH>0943253</Approval_Code_CH>
</TrxDetailCard>
<TrxDetailCard>
<TRX_HD_Key>18683825</TRX_HD_Key>
<Date_DT>2015-10-23T21:32:00.233+00:00</Date_DT>
<TRX_Card_Key>15263569</TRX_Card_Key>
<Total_Amt_MN>32.0000</Total_Amt_MN>
<Result_CH>0 </Result_CH>
<Result_Txt_VC>APPROVED</Result_Txt_VC>
<Approval_Code_CH>093389</Approval_Code_CH>
</TrxDetailCard>
</RichDBDS>
I've not worked with xml much so I'm not sure how to search this for a specific amount. I can have several TrxDetailCards. I know how to get amount when I only have one TrxDetailCard but I need to return the TrxDetailCard for the hits on the amount that I need.
So if I am looking for the TrxDetailCard that is 32.00, I need the method to return:
<TrxDetailCard>
<TRX_HD_Key>18683825</TRX_HD_Key>
<Date_DT>2015-10-23T21:32:00.233+00:00</Date_DT>
<TRX_Card_Key>15263569</TRX_Card_Key>
<Total_Amt_MN>32.0000</Total_Amt_MN>
<Result_CH>0 </Result_CH>
<Result_Txt_VC>APPROVED</Result_Txt_VC>
<Approval_Code_CH>093389</Approval_Code_CH>
</TrxDetailCard>
How would I go about doing this?
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<RichDBDS>" +
"<TrxDetailCard>" +
"<TRX_HD_Key>18683435</TRX_HD_Key>" +
"<Date_DT>2015-10-22T21:32:00.233+00:00</Date_DT>" +
"<TRX_Card_Key>15263569</TRX_Card_Key>" +
"<Total_Amt_MN>22.0000</Total_Amt_MN>" +
"<Result_CH>0 </Result_CH>" +
"<Result_Txt_VC>APPROVED</Result_Txt_VC>" +
"<Approval_Code_CH>0943253</Approval_Code_CH>" +
"</TrxDetailCard>" +
"<TrxDetailCard>" +
"<TRX_HD_Key>18683825</TRX_HD_Key>" +
"<Date_DT>2015-10-23T21:32:00.233+00:00</Date_DT>" +
"<TRX_Card_Key>15263569</TRX_Card_Key>" +
"<Total_Amt_MN>32.0000</Total_Amt_MN>" +
"<Result_CH>0 </Result_CH>" +
"<Result_Txt_VC>APPROVED</Result_Txt_VC>" +
"<Approval_Code_CH>093389</Approval_Code_CH>" +
"</TrxDetailCard>" +
"</RichDBDS>";
XElement richDBDS = XElement.Parse(xml);
XElement results = richDBDS.Elements("TrxDetailCard").Where(x => (decimal)x.Element("Total_Amt_MN") == (decimal)32.0000).FirstOrDefault();
}
}
}
You can use Linq-to-Xml
var str = File.ReadAllText(#"C:\YourDirectory\sample.xml");
XDocument xDoc = XDocument.Parse(str);
var trxNodes = xDoc.Descendants("TrxDetailCard");
var node = trxNodes.First(n => double.Parse(n.Element("Total_Amt_MN").Value) == 32.00);
I want to fetch only 'Param1' from the below XML file.Please help.With my code it is giving me complete string of values of all attributes under SSIS Parameter Node but t is not giving Param1 in that.
XML File Contents:`
<?xml version="1.0"?>
<SSIS:Parameters xmlns:SSIS="www.microsoft.com/SqlServer/SSIS">
<SSIS:Parameter
SSIS:Name="param1">
<SSIS:Properties>
<SSIS:Property
SSIS:Name="ID">{6fc5a81b-723b-4821-b948-0cbd44d86c84}</SSIS:Property>
<SSIS:Property
SSIS:Name="CreationName"></SSIS:Property>
<SSIS:Property
SSIS:Name="Description"></SSIS:Property>
<SSIS:Property
SSIS:Name="IncludeInDebugDump">0</SSIS:Property>
<SSIS:Property
SSIS:Name="Required">0</SSIS:Property>
<SSIS:Property
SSIS:Name="Sensitive">0</SSIS:Property>
<SSIS:Property
SSIS:Name="Value"></SSIS:Property>
<SSIS:Property
SSIS:Name="DataType">18</SSIS:Property>
</SSIS:Properties>
</SSIS:Parameter>
</SSIS:Parameters>
`
My Code Snippet:
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNodeList xmlnode;
int i = 0;
string str = null;
FileStream fs = new FileStream(#"D:\Sample SSIS\sampleDeploymentDemo\sampleDeploymentDemo\Project.params", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
xmlnode = xmldoc.GetElementsByTagName("SSIS:Parameters");
for (i = 0; i <= xmlnode.Count - 1; i++)
{
xmlnode[i].ChildNodes.Item(0).InnerText.Trim();
str = xmlnode[i].InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(1).InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(2).InnerText.Trim();
Console.WriteLine(str);
}
Console.ReadLine();
"param1" is attribute. You can get it with followed code:
...
xmlnode = xmldoc.GetElementsByTagName("SSIS:Parameters");
for (i = 0; i <= xmlnode.Count - 1; i++)
{
var val = xmlnode[i].FirstChild.Attributes["SSIS:Name"].Value;
Console.WriteLine(val);
}
Console.ReadLine();
...
See this link
Try XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants().Where(x => x.Name.LocalName == "Parameter").Descendants().Where(y => y.Name.LocalName == "Property").Select(z => new
{
value = z.Attributes().Where(a => a.Name.LocalName == "Name").Select(b => b.Value).FirstOrDefault()
}).ToList();
foreach (var item in results)
{
Console.WriteLine(item.value);
}
}
}
}
I am trying to export the data from a data table into xml file. I have this part working but when a record does not have any data or a white space it still writes the it in the xml file with XML:space Preserved.
I want to ignore the columns and not have them in xml file if they do not have any data in them
example of the xml file it is producing now
I want customer street 3 and 4 nodes to be not printed if they don't have any values in them.
here is my code
using System.IO;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml.Linq;
using System;
using System.Collections.Generic;
using PdfSharp.Pdf.IO;
using PdfSharp.Pdf;
using PdfSharp.Drawing;
using System.Xml;
namespace InvoicePrintProgram
{
class XMLGenerator
{
//Defining method that generates XMl Files
public void Start(String XmlFilepath, string XMlFileName, DataTable DT, int PageCountOut, int SequenceCountOut, int[] PrefIndex/*, int[] SequenceIndex, IEnumerable<String> chunk, int IndexCount out int IndexCountOut*/)
{
// Creates Xml file from datatable using the wrtieXml method
FileStream streamWrite = new FileStream(XmlFilepath, System.IO.FileMode.Create);
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Indent = true;
//settings.Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1")
settings.Encoding = System.Text.Encoding.UTF8;
settings.CloseOutput = true;
settings.CheckCharacters = true;
settings.NewLineChars = "\r\n";
DT.WriteXml(streamWrite, XmlWriteMode.IgnoreSchema);
You can create a List of Object from that DataTable and use something like this:
List<string> xml_string = new List<string>();
xml_string.Add("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
xml_string.Add("anything you need as header");
foreach(string current_string in your_object_of_DataTable)
{
if(current_string!=null || current_string.Trim()!="")
{
xml_string.Add("<Your Tag>"+current_string+"</Your Tag>");
}
}
try
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"D:\xml_file_name.xml"))
{
foreach (string line in xml_string)
{
file.WriteLine(line);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
MessageBox.Show("File exported.");
}