Parse Big XML file using XMLReader - c#

I have a very big xml file with below format
<ABC>
<NAMEDETAILS></NAMEDETAILS>
<PRODUCT>
<PRODUCTDETAILS>
<ProductName>
<name>Car</Name>
<name>lorry<name>
<name>Car<name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCTDETAILS>
<ProductName>
<name>van</Name>
<name>cycle</Name>
<name>bus</Name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCTDETAILS>
<ProductName>
<name>car</Name>
<name>cycle</Name>
<name>bus</Name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCT>
</ABC>
I want to retrieve the PRODUCTDETAILS data whose name tag has the value "car" and save it in a new xml file. I am using XMLReader but i am stuck in moving forward. Can somebody help me. Below is the c# code
XMLReader xmlReader = XMLReader.Create(#"\\Drive\xmlfile.xml")
while (xmlReader.Read())
{
If (xmlReader.NodeType == XMLNodeType.Element) && (xmlReader.Name == "PRODUCTDETAILS")
{
xmlReader.ReadtoDescendant("ProductName")
}
}

using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace ConApp1
{
class Program
{
static void Main()
{
using (var xmlWriter = XmlWriter.Create("result.xml"))
using (var xmlReader = XmlReader.Create("test.xml"))
{
xmlWriter.WriteStartElement("PRODUCT");
while (xmlReader.ReadToFollowing("PRODUCTDETAILS"))
{
using (var nodeReader = xmlReader.ReadSubtree())
{
nodeReader.MoveToContent();
var elem = (XElement)XNode.ReadFrom(nodeReader);
var name = elem.Descendants("name").First().Value;
if (name.Equals("car", StringComparison.OrdinalIgnoreCase))
{
elem.WriteTo(xmlWriter);
}
}
}
}
}
}
}
Since you say that the file is large, both reading and writing should be done using streaming tools. XmlWriter is used for writing. This guarantees low memory consumption and no OutOfMemoryException occurs.

Try following :
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 INPUT_FILENAME = #"c:\temp\test.xml";
const string OUTPUT_FILENAME = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(INPUT_FILENAME);
string header = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Cars></Cars>";
XDocument doc = XDocument.Parse(header);
XElement cars = doc.Root;
while (!reader.EOF)
{
if (reader.Name != "PRODUCTDETAILS")
{
reader.ReadToFollowing("PRODUCTDETAILS");
}
if (!reader.EOF)
{
XElement product = (XElement)XElement.ReadFrom(reader);
if(product.Descendants("name").Any(x => ((string)x).Trim() == "Car"))
{
cars.Add(product);
}
}
}
doc.Save(OUTPUT_FILENAME);
}
}
}

Related

During Xml deserialization, matrix is returning null

Got lots of trials to deserialize the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-down" compressionlevel="0" width="80" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="TilesetSA" tilewidth="16" tileheight="16" tilecount="4000" columns="80">
<image source="../../TilesetSA.png" width="1280" height="800"/>
</tileset>
<layer id="1" name="Walls" width="80" height="50">
<data encoding="csv">
3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,81,81,81,81,81,81,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,
</data>
</layer>
</map>
I don't have the opportunity to change the xml file, it must stay as is.
I Managed to retreive all attributes for "map", "tileset" and "image", but in the "layer" element, in can only retreive the attributes (id, name, width, height), the data element always remains null.
I created dedicated classes for "map", "tileset", "layer", "image" and "map".
Would anyone suggest me any code to solve this "null result" issue?
Use following xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication159
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string dataStr = (string)doc.Descendants("data").FirstOrDefault();
int[][] results = dataStr.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(y => int.Parse(y)).ToArray()).ToArray();
}
}
}
My code is as follow:
public virtual void WriteSaveXmlData(string pPath, int pRoom, bool pNewGame, int pX, int pY)
{
//xml save serialization
XmlSaving XmlGameSave = new XmlSaving();
XmlGameSave.SaveRootPath = pPath;
XmlGameSave.SavedCurrentRoom = pRoom;
XmlGameSave.XmlIsNewGame = pNewGame;
XmlGameSave.XHero = pX;
XmlGameSave.YHero = pY;
XmlSerializer xs = new XmlSerializer(typeof(XmlSaving));
using (StreamWriter wr = new StreamWriter(GameRound.GameSaveRootPath + GameRound.SaveFileName))
{
xs.Serialize(wr, XmlGameSave);
}
}
public virtual XmlSaving ReadSaveXmlData()
{
//xml save deserialization
XmlSerializer xs = new XmlSerializer(typeof(XmlSaving));
using (StreamReader rd = new StreamReader(GameRound.GameSaveRootPath + GameRound.SaveFileName))
{
XmlSaving XmlGameSave = xs.Deserialize(rd) as XmlSaving;
return XmlGameSave;
}
}
public virtual XmlMap ReadXmlMapData(string pPath, int RoomNumber)
{
XmlMap ReadTmxData = new XmlMap();
XmlSerializer TmxXmlMap = new XmlSerializer(typeof(XmlMap));
using (StreamReader rd = new StreamReader(pPath + #"P1\RoomMapSaphir0" + RoomNumber + ".tmx"))
{
ReadTmxData = TmxXmlMap.Deserialize(rd) as XmlMap;
return ReadTmxData;
}
}

Trying to create a program using linked list for character counting?

I am trying to create a program that is a character counter using
a linked list and I am struggling. I have to program this in C#. If anyone can see a solution please tell me. I am have troubling using a linked list with nodes trying to show the results of counting characters. What am I missing? What do I need to add? By the way I am using visual works to run my code.
(First file)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApp17
{
class CharacterFrequency
{
private char ch;
private int frequency;
public char Ch
{
get { return ch; }
set { ch = value; }
}
public int Frequency
{
get { return frequency; }
set { frequency = value; }
}
}
}
(Second file)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApp17
{
class Program
{
static void Main(string[] args)
{
int ch;
const int InputFile = 0;
const int OutputFile = 1;
StreamReader reader = null;
StreamWriter writer = null;
//Declaring Linked List
CharacterFrequency obj = new CharacterFrequency();
LinkedList list = new LinkedList<CharacterFrequency>();
//To read the characters in the Input File.
reader = new StreamReader(File.OpenRead(args[InputFile]));
//To insert text through the loop.
while ((ch = reader.Read()) != -1)
{
//Creating my linked list.
CharacterFrequency cf = LinkedList<CharacterFrequency>
list(ch);
//Creating my nodes.
LinkedListNode<CharacterFrequency> node;
node = list.Find(cf);
//Conditions
if (node != null)
{
node.Value.Add(cf, 1); //Increase in increments.
}
else
{
list.AddLast(cf); //If it is not on the list yet, add it.
}
}
reader.Close();
//Create my output file.
writer = new StreamWriter(File.OpenWrite(args[OutputFile]));
//Display on prompt.
foreach (CharacterFrequency cf in list)
writer.WriteLine(cf.ToString());
writer.Close();
}
}
}

I use ASP.net to generate a sitemap.xml, get Google Webmaster says: "Your Sitemap appears to be an HTML page."

I am trying to return an generated .xml file, but google picks it up as a html page. So I get: "Your Sitemap appears to be an HTML page. Please use a supported sitemap format instead."
Here is the ASP.net Controller that generate the sitemap.xml
[Route("sitemap.xml")]
public async Task<IActionResult> SitemapXmlAsync()
{
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("https://api.badgag.com/api/generateSitemap");
var response = await client.GetAsync("");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync();
var pages = JsonConvert.DeserializeObject<String[]>(stringResult);
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
xml += "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">";
foreach (string s in pages)
{
xml += "<sitemap>";
xml += "<loc>" + s + "</loc>";
//xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>";
xml += "</sitemap>";
}
xml += "</sitemapindex>";
return Content(xml, "text/xml");
}
catch (HttpRequestException httpRequestException)
{
return BadRequest($"Error getting sitemap: {httpRequestException.Message}");
}
}
}
I assume I am missing something. Setting a different header?
You can see the result here:
https://badgag.com/sitemap.xml
Thanks in advance :)
I found this article about creating a XML sitemap with ASP.Net, this helped me to create a sitemap.ashx file with the correct sitemap layout Google and Bing require.
It basically is using XmlTextWriter to generate the required tags for a sitemap. This example is using HTTPContext to write an XML file. Here is the code from this site:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Web;
using System.Xml;
namespace Mikesdotnetting
{
public class Sitemap : IHttpHandler
{
public void ProcessRequest(HttpContext context) {
context.Response.ContentType = "text/xml";
using (XmlTextWriter writer = new XmlTextWriter(context.Response.OutputStream, Encoding.UTF8)) {
writer.WriteStartDocument();
writer.WriteStartElement("urlset");
writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
writer.WriteStartElement("url");
string connect = ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString;
string url = "http://www.mikesdotnetting.com/";
using (SqlConnection conn = new SqlConnection(connect)) {
using (SqlCommand cmd = new SqlCommand("GetSiteMapContent", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// Get the date of the most recent article
rdr.Read();
writer.WriteElementString("loc", string.Format("{0}Default.aspx", url));
writer.WriteElementString("lastmod", string.Format("{0:yyyy-MM-dd}", rdr[0]));
writer.WriteElementString("changefreq", "weekly");
writer.WriteElementString("priority", "1.0");
writer.WriteEndElement();
// Move to the Article IDs
rdr.NextResult();
while (rdr.Read()) {
writer.WriteStartElement("url");
writer.WriteElementString("loc", string.Format("{0}Article.aspx?ArticleID={1}", url, rdr[0]));
if (rdr[1] != DBNull.Value)
writer.WriteElementString("lastmod", string.Format("{0:yyyy-MM-dd}", rdr[1]));
writer.WriteElementString("changefreq", "monthly");
writer.WriteElementString("priority", "0.5");
writer.WriteEndElement();
}
// Move to the Article Type IDs
rdr.NextResult();
while (rdr.Read()) {
writer.WriteStartElement("url");
writer.WriteElementString("loc", string.Format("{0}ArticleTypes.aspx?Type={1}", url, rdr[0]));
writer.WriteElementString("priority", "0.5");
writer.WriteEndElement();
}
// Finally move to the Category IDs
rdr.NextResult();
while (rdr.Read()) {
writer.WriteStartElement("url");
writer.WriteElementString("loc", string.Format("{0}Category.aspx?Category={1}", url, rdr[0]));
writer.WriteElementString("priority", "0.5");
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
}
context.Response.End();
}
}
}
}
public bool IsReusable {
get {
return false;
}
}
}
}
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 URL = #"https://badgag.com/sitemap.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(URL);
XNamespace ns = doc.Root.GetDefaultNamespace();
string[] locations = doc.Descendants(ns + "loc").Select(x => (string)x).ToArray();
}
}
}

Handling complex types xml-reader in c#

for example i have following XML:
I want to read the Sender object with an XML-Reader:
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
I wrote following parser:
using (var reader = XmlReader.Create(new FileStream(Console.ReadLine(), FileMode.Open, FileAccess.ReadWrite, FileShare.Read)))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.LocalName)
{
case "Sender":
do
{
reader.Read();
} while (reader.LocalName != "name");
Console.WriteLine("Sended from:" + reader.ReadElementContentAsString());
break;
}
}
}
}
That isn't quite elegant, is there another method with the Xml-reader, or is this the only way?
R3turnz
This is the best method. Always work without errors. Uses XmlReader and xml Linq.
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)
{
using (var reader = XmlReader.Create(new FileStream(Console.ReadLine(), FileMode.Open, FileAccess.ReadWrite, FileShare.Read)))
{
while (!reader.EOF)
{
if (reader.Name != "name")
{
reader.ReadToFollowing("name");
}
if(!reader.EOF)
{
XElement name = (XElement)XElement.ReadFrom(reader);
}
}
}
}
}
}
thank you for your answers. But i tried to ask for another method WITH THE XML-READER. I will have a look at the other
If there is a single element name, we can use the simplest code:
string path = "..."; // path to file
string ns = "..."; // specify correct namespace
using (var reader = XmlReader.Create(path))
{
reader.ReadToFollowing("name", ns);
string name = reader.ReadElementContentAsString();
Console.WriteLine(name);
}
If there are many nodes Sender and name, and must properly consider the level of nesting, we have to complicate the code:
using (var reader = XmlReader.Create(path))
{
while (reader.ReadToFollowing("Sender", ns))
{
using (var innerReader = reader.ReadSubtree())
{
if (innerReader.ReadToFollowing("name", ns))
{
string name = innerReader.ReadElementContentAsString();
Console.WriteLine(name);
break;
}
}
}
}
In my view, it's more elegant and correct.
you know how to try it, but write the file you use in the "NAME" section is worth a try, man.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using (XmlReader xmlreader = XmlTextReader.Create(xmlStream))
{
while (xmlreader.Read())
{
if (xmlreader.IsStartElement())
{
switch (xmlreader.Name) // folder variable
{
case "NAME": // xml in label variable
if (xmlreader.Read())
{
Names_List.Add(xmlreader.Value.Trim());
NumLabels += 1; //order of the column in the xml file
}
}
}
}
}

LINQ to XML - Nothing is binding?

I am trying to parse from XML, but for some reason nothing is being disaplyed in my text boxes that I have binding for the variables.
I havae tried al sorts of variation sof Xdocuemnt or Xelement, but it doesn't seem to work. The XML structure seems fairly straight forward, so I can't figure out what is going wrong.
Any help would be appreciated.
edit************
All working now. Thanks for our help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Xml.Linq;
namespace TradeMe
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
WebClient Trademe = new WebClient();
Trademe.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Trademe_DownloadStringCompleted);
Trademe.DownloadStringAsync(new Uri ("http://api.trademe.co.nz/v1/Search/General.xml?search_string=" + TradeSearch.Text));
}
void Trademe_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
var r = XDocument.Parse(e.Result);
// Declare the namespace
XNamespace ns = "http://api.trademe.co.nz/v1";
listBox1.ItemsSource = from TM in r.Root.Descendants(ns + "Listing")
select new TradeItem
{
//ImageSource = TM.Element(ns + "Listing").Element(ns + "PictureHref").Value,
Message = TM.Element(ns + "Title").Value,
UserName = TM.Element(ns + "Region").Value
};
}
public class TradeItem
{
public string UserName { get; set; }
public string Message { get; set; }
public string ImageSource { get; set; }
}
}
}
XML looks like this.
<SearchResults xmlns="http://api.trademe.co.nz/v1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<TotalCount>12723</TotalCount>
<Page>1</Page>
<PageSize>50</PageSize>
- <List>
- <Listing>
<ListingId>399739762</ListingId>
<Title>Playstation 3 320GB Slim going at $1 Reserve</Title>
<Category>0202-6205-6207-</Category>
<StartPrice>1.0000</StartPrice>
<StartDate>2011-08-14T22:52:28.833Z</StartDate>
<EndDate>2011-08-21T08:45:00Z</EndDate>
<ListingLength i:nil="true" />
<HasGallery>true</HasGallery>
<MaxBidAmount>400.0000</MaxBidAmount>
<AsAt>2011-08-18T19:33:41.4561556Z</AsAt>
<CategoryPath>/Gaming/PlayStation-3/Consoles</CategoryPath>
<PictureHref>http://images.trademe.co.nz/photoserver/thumb/27/183787627.jpg</PictureHref>
<RegionId>2</RegionId>
<Region>Auckland</Region>
<BidCount>137</BidCount>
<IsReserveMet>true</IsReserveMet>
<HasReserve>true</HasReserve>
<NoteDate>1970-01-01T00:00:00Z</NoteDate>
<ReserveState>Met</ReserveState>
<PriceDisplay>$400.00</PriceDisplay>
</Listing>
Try this:
// Declare the namespace
XNamespace ns = "http://api.trademe.co.nz/v1";
listBox1.ItemsSource = from TM in r.Root.Descendants(ns+"List")
select new TradeItem
{
ImageSource = TM.Element(ns+"Listing")
.Element(ns+"PictureHref").Value,
Message = TM.Element(ns+"PageSize").Value,
UserName = TM.Element(ns+"SearchResults").Element(ns+"Page").Value
};
Nothing is matching because you did not specify the namespace. See the sample code at MSDN, repeated here:
XElement root = XElement.Parse(
#"<Root xmlns='http://www.adventure-works.com'>
<Child>1</Child>
<Child>2</Child>
<Child>3</Child>
<AnotherChild>4</AnotherChild>
<AnotherChild>5</AnotherChild>
<AnotherChild>6</AnotherChild>
</Root>");
XNamespace aw = "http://www.adventure-works.com";
IEnumerable<XElement> c1 =
from el in root.Elements(aw + "Child")
select el;
Console.WriteLine("Result set follows:");
foreach (XElement el in c1)
Console.WriteLine((int)el);
Console.WriteLine("End of result set");

Categories

Resources