Is it possible to copy all content(xml fragment) from one stream(using xmlReader) to second (xmlWriter).
I have some procedures which return xml fragments.
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
using (XmlWriter writer = XmlWriter.Create(stream, _settings))
{
writer.WriteStartElement(typeName);
writer.WriteAttributeString("RowVersion", rowVersion);
for (int i = 1; i <= packagesCount; i++)
{
cmd.Parameters["#packageNumber"].Value = i;
using (var r = cmd.ExecuteXmlReader())
{
//need copy all fragment from reader
}
writer.WriteEndElement();
}
}
There is method like writer.WriteNode(reader,true), but using this I need to iterate all elements. It's not effective when I have 10000 elements in one fragment. I need just copy all content. Moreover this fragment could be very big, that's why I prefer to use stream, than saving it in string
An old post but for someone may be useful.
I have to deal with XML files that are fairly big (>50MB). And I need to extract a segment from them and work with that segments separately. So I did this:
class Program
{
static void processXML(string xml)
{
SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);
XmlReader reader = XmlReader.Create(xml);
XmlWriterSettings settings = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Auto
};
var output_file = "output.xml";
if (File.Exists(output_file))
{
File.Delete(output_file);
}
XmlWriter writer = XmlWriter.Create("output.xml", settings);
try
{
Console.WriteLine("Processing: " + xml);
Console.WriteLine("Outputting to: " + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "output.xml"));
//extract all namespaces used in document
XPathDocument x = new XPathDocument(reader);
XPathNavigator foo = x.CreateNavigator();
foo.MoveToFollowing(XPathNodeType.Element);
IDictionary<string, string> Namespaces = foo.GetNamespacesInScope(XmlNamespaceScope.All);
reader = XmlReader.Create(xml);
var elementFullName_ = "";
var elementName_ = "";
var elementToFind = "sl:stand";
var elementsFound = 0;
var prefix_ = "";
var text_ = "";
var whiteSpace_ = "";
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
elementFullName_ = reader.Name;
if (elementFullName_ == elementToFind)
{
//avoid processing the file if XmlWriter just started
if (writer.WriteState != WriteState.Start)
{
writer.Flush();
writer.Close();
//here process the file for whatever you want
if (File.Exists(output_file))
{
File.Delete(output_file);
}
writer = XmlWriter.Create("output.xml", settings);
}
elementsFound = 1;
}
else if(elementsFound > 0)
{
elementsFound++;
}
var arr = reader.Name.Split(':');
if (arr.Length == 2)
{
prefix_ = arr[0];
elementName_ = arr[1];
if (elementsFound > 0)
writer.WriteStartElement(arr[0], arr[1], Namespaces[arr[0]]);
}
else
{
prefix_ = "";
elementName_ = reader.Name;
if (elementsFound > 0)
writer.WriteStartElement(reader.Name);
}
if (elementsFound > 0 && reader.HasAttributes)
writer.WriteAttributes(reader, true);
if (elementsFound > 0 && reader.IsEmptyElement)
writer.WriteEndElement();
break;
case XmlNodeType.EndElement:
if (elementsFound > 0)
{
writer.WriteEndElement();
}
if (elementsFound > 0)
{
elementsFound--;
}
if (elementsFound == 0)
{
}
break;
case XmlNodeType.Text:
if (elementFullName_ == "gml:posList")
{
text_ = reader.Value;
}
if (elementsFound > 0)
writer.WriteString(reader.Value);
break;
case XmlNodeType.Whitespace:
if (elementFullName_ == "gml:posList")
{
whiteSpace_ = reader.Value;
}
if (elementsFound > 0)
writer.WriteWhitespace(reader.Value);
break;
}
}
}
finally
{
reader.Close();
writer.Close();
}
}
static void Main(string[] args)
{
var xml = "";
if (args.Length == 0 || !File.Exists(args[0]))
{
Console.WriteLine("Please, provide a valid XML file as a commandline parameter");
return;
}
xml = args[0];
processXML(xml);
Console.WriteLine("Done!");
}
}
Note: some conditions are not important to you so you can remove them.
Related
I am trying to retrieve all elements from an XML file, but I just can reach one, is there any way I can retrieve all?
HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
using (XmlReader reader = XmlReader.Create(new StreamReader(objResponse.GetResponseStream())))
{
while (reader.Read())
{
#region Get Credit Score
//if (reader.ReadToDescendant("results"))
if (reader.ReadToDescendant("ssnMatchIndicator"))
{
string ssnMatchIndicator = reader.Value;
}
if (reader.ReadToDescendant("fileHitIndicator"))
{
reader.Read();//this moves reader to next node which is text
result = reader.Value; //this might give value than
Res.Response = true;
Res.SocialSecurityScore = result.ToString();
//break;
}
else
{
Res.Response = false;
Res.SocialSecurityScore = "Your credit score might not be available. Please contact support";
}
#endregion
#region Get fileHitIndicator
if (reader.ReadToDescendant("fileHitIndicator"))
{
reader.Read();
Res.fileHitIndicator = reader.Value;
//break;
}
#endregion
}
}
Can somebody help me out with this issue?
I am also using objResponse.GetResponseStream() because the XML comes from a response from server.
Thanks a lot in advance.
Try this :
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNodeList xmlnode ;
int i = 0;
string str = null;
FileStream fs = new FileStream("product.xml", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
xmlnode = xmldoc.GetElementsByTagName("Product");
for (i = 0; i <= xmlnode.Count - 1; i++)
{
xmlnode[i].ChildNodes.Item(0).InnerText.Trim();
str = xmlnode[i].ChildNodes.Item(0).InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(1).InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(2).InnerText.Trim();
MessageBox.Show (str);
}
I don't know why what you're doing is not working, but I wouldn't use that method. I've found the following to work well. Whether you're getting the xml from a stream, just put it into a string and bang...
StreamReader reader = new StreamReader(sourcepath);
string xml = reader.ReadToEnd();
reader.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList list = doc.GetElementsByTagName("*");
foreach (XmlNode nd in list)
{
switch (nd.Name)
{
case "ContactID":
var ContactIdent = nd.InnerText;
break;
case "ContactName":
var ContactName = nd.InnerText;
break;
}
}
To capture what is between the Xml tags, if there are no child Xml tags, use the InnerText property, e.g. XmlNode.InnerText. To capture what is between the quotes in the nodes' attributes, use XmlAttribute.Value.
As for iterating through the attributes, if one of your nodes has attributes, such as the elements "Name", "SpectralType" and "Orbit" in the Xml here:
<System>
<Star Name="Epsilon Eridani" SpectralType="K2v">
<Planets>
<Planet Orbit="1">Bill</Planet>
<Planet Orbit="2">Moira</Planet>
</Planets>
</Star>
</System>
Detect them using the Attributes property, and iterate through them as shown:
if (nd.Attributes.Count > 0)
{
XmlAttributeCollection coll = nd.Attributes;
foreach (XmlAttribute cn in coll)
{
switch (cn.Name)
{
case "Name":
thisStar.Name = cn.Value;
break;
case "SpectralType":
thisStar.SpectralClass = cn.Value;
break;
}
}
}
You might find some more useful information HERE.
Below is a sample of the type of XML file I am trying to handle. If I have only one part along with an accompanying number/character I can process the data extraction without the necessity of the 'if (!reader.EOF)' control structure. However when I try to include this structure so that I can loop back to checking for another part, number, and character group, it deadlocks.
Any advice as to how to do this properly? This was the most efficient idea that popped into my head. I am new to reading data from XMLs.
Sample Xml:
<?xml version="1.0" encoding="UTF-8"?>
<note>
<part>100B</part>
<number>45</number>
<character>a</character>
<part>100C</part>
<number>55</number>
<character>b</character>
</note>
Code:
String part = "part";
String number = "number";
String character = "character";
String appendString = "";
StringBuilder sb = new StringBuilder();
try
{
XmlTextReader reader = new XmlTextReader("myPath");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
myLabel:
if (reader.Name == part)
{
part = reader.ReadInnerXml();
}
if (reader.Name == number)
{
number = reader.ReadInnerXml();
number = double.Parse(number).ToString("F2"); //format num
}
if (reader.Name == character)
{
character = reader.ReadInnerXml();
}
//new string
appendString = ("Part: " + part + "\nNumber: " + number +
"\nCharacter: " + character + "\n");
//concatenate
sb.AppendLine(appendString);
if (reader.EOF != true)
{
Debug.Log("!eof");
part = "part";
number = "number";
character = "character";
goto myLabel;
}
//print fully concatenated result
sb.ToString();
//reset string builder
sb.Length = 0;
break;
}
}
}
catch (XmlException e)
{
// Write error.
Debug.Log(e.Message);
}
catch (FileNotFoundException e)
{
// Write error.
Debug.Log(e);
}
catch(ArgumentException e)
{
// Write error.
Debug.Log(e);
}
XmlReader class has many useful methods. Use it.
See this:
var sb = new StringBuilder();
using (var reader = XmlReader.Create("test.xml"))
{
while (reader.ReadToFollowing("part"))
{
var part = reader.ReadElementContentAsString();
sb.Append("Part: ").AppendLine(part);
reader.ReadToFollowing("number");
var number = reader.ReadElementContentAsDouble();
sb.Append("Number: ").Append(number).AppendLine();
reader.ReadToFollowing("character");
var character = reader.ReadElementContentAsString();
sb.Append("Character: ").AppendLine(character);
}
}
Console.WriteLine(sb);
Alexander's answer is fine, I just want to add sample using XDocument, according comments of Jon Skeet:
var sb = new StringBuilder();
var note = XDocument.Load("test.xml").Root.Descendants();
foreach (var el in note)
{
sb.Append(el.Name).Append(": ").AppendLine(el.Value);
}
Console.WriteLine(sb);
I am trying to find a way to save data back to an xml file with an encoding "iso-8859-7".
firstly am loading the xml using
public XmlDocument LoadDocument(String x)
{
XmlDocument document = new XmlDocument();
StreamReader stream = new StreamReader(xml, Encoding.GetEncoding("iso-8859-7"));
document.Load(stream);
return (document);
}
to load attributes inside form controls and then when the save button is clicked
private void savebtn_Click(object sender, EventArgs e)
{
XmlNodeList attributes = commonMethods.LoadDocument(xml).DocumentElement.SelectNodes("//Class[#Name='" + classname + "']/Property[#Id='" + id + "']/attribute::*");
for (int x = 0; x < attributes.Count; )
{
foreach (Control ctr in table1.Controls)
{
if (ctr is TextBox)
{
if (ctr.Text == attributes[x].Value.ToString()) { x++; }
else
{
attributes[x].Value = ctr.Text; commonMethods.SaveDocument(xml);
x++;
}
}
else if (ctr is ComboBox)
{
if (((ComboBox)ctr).Text == attributes[x].Value) { x++; }
else
{
attributes[x].Value = ((ComboBox)ctr).Text; commonMethods.SaveDocument(xml);
x++;
}
}
}
}
}
it saves the changes back to the xml file. I used to save it without using xmlwriter like xmldoc.Save("sample.xml) but because of some characters inside the file I had to use a different approach like.
public XmlDocument SaveDocument(String x)
{
XmlDocument document = new XmlDocument();
StreamWriter stream = new StreamWriter(x,false,Encoding.GetEncoding("iso-8859-7"));
document.Save(xml);
return (document);
}
The problem is when I compile it says "xml is used by another process" and it fails.
System.IO.IOException
You've got this exception because the file is still opened by the StreamReader that is pending for finalization (garbage collection).
You should always dispose your streams (and reader / writers) to release the file handle as soon as possible.
public XmlDocument LoadDocument(String path)
{
XmlDocument document = new XmlDocument();
using (StreamReader stream = new StreamReader(path, Encoding.GetEncoding("iso-8859-7")))
{
document.Load(stream);
}
return (document);
}
public XmlDocument SaveDocument(XmlDocument document, String path)
{
using (StreamWriter stream = new StreamWriter(path,false,Encoding.GetEncoding("iso-8859-7")))
{
document.Save(stream);
}
return (document);
}
private void savebtn_Click(object sender, EventArgs e)
{
var doc = commonMethods.LoadDocument(xml);
XmlNodeList attributes = doc.DocumentElement.SelectNodes("//Class[#Name='" + classname + "']/Property[#Id='" + id + "']/attribute::*");
for (int x = 0; x < attributes.Count; )
{
foreach (Control ctr in table1.Controls)
{
if (ctr is TextBox)
{
if (ctr.Text == attributes[x].Value.ToString()) { x++; }
else
{
attributes[x].Value = ctr.Text; commonMethods.SaveDocument(doc, xml);
x++;
}
}
else if (ctr is ComboBox)
{
if (((ComboBox)ctr).Text == attributes[x].Value) { x++; }
else
{
attributes[x].Value = ((ComboBox)ctr).Text; commonMethods.SaveDocument(doc, xml);
x++;
}
}
}
}
}
you didn't dispose the StreamReader object after loading the document
add the using statement:
public XmlDocument LoadDocument(String x)
{
XmlDocument document = new XmlDocument();
using (StreamReader stream = new StreamReader(xml, Encoding.GetEncoding("iso-8859-7")))
{
document.Load(stream);
}
return (document);
}
reference: http://msdn.microsoft.com/en-us/library/system.io.streamreader(v=vs.110).aspx
i am created one xml file name is data.xml in this xml file i am storing this information
like bellow
<products>
<cloths Id="1">
<ClothName>Sharts</ClothName>
<Size>40</Size>
<Price>1050</Price>
<Amount>1000000</Amount>
<images>c:\users\venkateshg\documents\visual studio 2010\Projects\WebApplication1\WebApplication1\ImgUpload\Tulips.jpg</images>
</cloths>
</products>
This is a C# Code i devloped
XmlDocument XDoc = new XmlDocument(); // root
XmlElement XElemRoot = XDoc.CreateElement("products");
XDoc.AppendChild(XElemRoot);
XmlElement XCloths = XDoc.CreateElement("cloths");
DataSet ds = new DataSet();
ds.ReadXml(Server.MapPath("data.xml"));
int idval ;
if (ds.Tables[0].Rows.Count > 1)
{
idval = ds.Tables[0].Columns[5][0];
if (idval == 0)
{
idval = 1;
}
else
{
idval += 1;
}
}
else
{
idval = 1;
}
XCloths.SetAttribute("Id",idval.ToString());
XElemRoot.AppendChild(XCloths);
XmlElement XClothName = XDoc.CreateElement("ClothName");
XClothName.InnerText = TextBox1.Text;
XCloths.AppendChild(XClothName);
XmlElement XSize = XDoc.CreateElement("Size");
XSize.InnerText = TextBox2.Text; ;
XCloths.AppendChild(XSize);
XmlElement XPrice = XDoc.CreateElement("Price");
XPrice.InnerText = TextBox3.Text;
XCloths.AppendChild(XPrice);
XmlElement XAmount = XDoc.CreateElement("Amount");
XAmount.InnerText = "1000000";
XCloths.AppendChild(XAmount);
FileUpload1.ToolTip = "Select Image For Upload...";
string ext = System.IO.Path.GetExtension(this.FileUpload1.PostedFile.FileName);
if (FileUpload1.HasFile)
{
//Check File is available in Fileupload control and then upload to server path
string fname = FileUpload1.FileName;
//spath = #"~\ImgUpload\" + FileUpload.FileName;
string fpath = Server.MapPath("ImgUpload");
fpath = fpath + #"\" + FileUpload1.FileName;
string getext = System.IO.Path.GetExtension(FileUpload1.PostedFile.FileName);
string filename = System.IO.Path.GetFileNameWithoutExtension(FileUpload1.PostedFile.FileName);
string strFilePath = filename + DateTime.Now.ToString("yyyyMMdd") + getext;
if (getext != ".JPEG" && getext != ".jpeg" && getext != ".JPG" && getext != ".jpg" && getext != ".png" && getext != ".tif" && getext != ".tiff")
{
Page.ClientScript.RegisterStartupScript(typeof(Page), "successfull", "alert('Please upload only jpeg, jpg,png,tif,tiff'); window.location = 'Default.aspx';", true);
}
else
{
FileUpload1.SaveAs(Server.MapPath(#"~\ImgUpload\" + strFilePath));
Image1.ImageUrl = #"~\ImgUpload\" + strFilePath;
ViewState["fname"] = fname;
ViewState["fPath"] = #"~\ImgUpload\" + strFilePath;
XmlElement Ximages = XDoc.CreateElement("images");
Ximages.InnerText = fpath;
XCloths.AppendChild(Ximages);
}
}
else
{
}**
The problem is if i submitting each time the date is going to Reload the same id "1"
i want to continue to id 1,2,3,4,5................in one xml file
Unless you have some intricate purpose for your dataset, I believe you can drop it entirely.
Then you'd have something as follows:
XDocument xDoc;
int lastId = 0;
var path = Server.MapPath("data.xml");
if (File.Exists(path))
{
xDoc = XDocument.Load(path);
var existingCloths = xDoc.Root.Elements("cloths");
if (existingCloths.Any())
{
lastId = existingCloths.Max(c => Int32.Parse(c.Attribute("Id").Value));
}
}
else
{
xDoc = new XDocument(new XElement("products"));
}
var xCloths = XDoc.CreateElement("cloths");
xDoc.Add(new XAttribute("Id",
(lastId + 1).ToString(CultureInfo.InvariantCulture));
xDoc.Root.Add(xCloths);
//[...]
I personally find it significantly easier to just create a Class and serialize and deserialize to xml.
If you want to customize the Class you will need to add in the appropriate [XMLRoot] [XMLElement] and [XMLAttribute] tags to the Products class
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
namespace UShort
{
class Program
{
static void Main(string[] args)
{
Products prod = new Products();
prod.Cloths = new List<Products.cloths>();
Products.cloths jacket = new Products.cloths();
jacket.ClothName = "MyJacket";
jacket.amount = 12345;
jacket.price = (float)123.45;
jacket.size = 12;
jacket.images = "c:\\asdasd.jpg";
prod.Cloths.Add(jacket);
// String contining XML. Do what you want with it.
string ProductXML = XMLTools.convertObjToXMLString(prod);
// Create an object from an XML string of the same format.
Products NewProduct = (Products)XMLTools.convertXMLStringToObject(ProductXML, typeof(Products));
}
public class Products
{
public List<cloths> Cloths = new List<cloths>();
public class cloths
{
public string ClothName = string.Empty;
public int size = 0;
public float price = 0;
public long amount = 0;
public string images = string.Empty;
}
}
public static class XMLTools
{
/// <summary>
/// Overwrites the encoding to use UTF-8
/// </summary>
private class Utf8StringWriter : StringWriter
{
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
public static string convertObjToXMLString(object obj)
{
try
{
XmlSerializer serObj = new XmlSerializer(obj.GetType());
Utf8StringWriter sw = new Utf8StringWriter();
XmlTextWriter xtw = new XmlTextWriter(sw);
xtw.Formatting = Formatting.Indented;
serObj.Serialize(xtw, obj);
return sw.ToString();
}
catch (Exception)
{
throw;
}
}
public static object convertXMLStringToObject(string xmlString, Type objectType)
{
try
{
TextReader txr = new StringReader(xmlString);
XmlSerializer serObj = new XmlSerializer(objectType);
return serObj.Deserialize(txr);
}
catch (Exception)
{
throw;
}
}
}
}
}
I want to generate a million record xml file.For this i have a sample xml file with only one value set.Using this xml file fill ramdom values a million times.
I created a solutin but it is very time consuming one.My code is
try
{
label1.Text = "File creation in progress ...";
Random rnd = new Random();
string sStartupPath = Application.StartupPath;
string sName = "";
int flag = 0;
XmlDocument XmlFile = new XmlDocument();
XmlFile.Load(sStartupPath + #"..\..\..\BankStatement.xml");
XmlFile.Save(#"C:\XmlData\Bank.xml");
XmlDocument XmlF = new XmlDocument();
XmlF.Load(#"C:\XmlData\Bank.xml");
long k = Convert.ToInt32(textBox1.Text);
for (int j = 1; j < k; j++)
{
XmlTextReader objXmlTextReader = new XmlTextReader(sStartupPath + #"..\..\..\BankStatement.xml");
while (objXmlTextReader.Read())
{
switch (objXmlTextReader.NodeType)
{
case XmlNodeType.Element:
sName = objXmlTextReader.Name;
if (sName == "DataXml")
{
if (flag == 0)
flag = 1;
}
break;
case XmlNodeType.Text:
if (flag == 1)
{
XmlNodeList elemList = XmlFile.GetElementsByTagName(sName);
for (int i = 0; i < elemList.Count; i++)
{
if (elemList[i].Name == "Name")
elemList[i].InnerXml = generateNames();
else if (elemList[i].Name == "EmailID")
elemList[i].InnerXml = generatemailids();
else
elemList[i].InnerXml = rnd.Next(500000).ToString();
}
}
break;
case XmlNodeType.EndElement:
sName = objXmlTextReader.Name;
if (sName == "DataXml")
{
if (flag == 1)
flag = 0;
}
break;
}
}
XmlDocument dd = new XmlDocument();
dd.LoadXml(XmlFile.InnerXml);
XmlNodeList node=dd.GetElementsByTagName("Customers");
XmlDocumentFragment xfrag = XmlF.CreateDocumentFragment();
xfrag.RemoveAll();
for (int i = 0; i < 1; i++)
{
xfrag.InnerXml = node[i].InnerXml;
XmlF.DocumentElement.FirstChild.AppendChild(xfrag);
}
XmlF.Save(#"C:\XmlData\Bank.xml");
}
label1.Visible = false;
MessageBox.Show("File creation success..!");
}
catch (Exception ex)
{
label1.Text = "";
MessageBox.Show("Error Occured");
}
Please give me a better solution.
The fastest method I know to write XML (short of building the XML fragments manually) is to use XmlWriter
The XmlWriter class is an abstract base class that provides a
forward-only, write-only, non-cached way of generating XML streams. It
can be used to build XML documents that conform to the W3C Extensible
Markup Language (XML) 1.0 (fourth edition) recommendation and the
Namespaces in XML recommendation.
MSDN has a walkthrough on how to use the abstract XmlWriter class.
For writing large XML files you should use XmlTextWriter.