I want to create XML document with multiple elements inside. The format should be something like this:
<Item>
<Id>2276138</Id>
<Title>92907-03100-00 WASHER, CHAIN</Title>
<Link>http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00</Link>
<Price>0.0000</Price>
<Description>WASHER, CHAIN (92907-03100-00)</Description>
<Condition>New</Condition>
<Brand />
<Product_Type />
<Availability>In Stock</Availability>
<Manufacturer>Suzuki</Manufacturer>
</Item>
Everything is ok after the first loop of fetching data, but once the 2nd loop is done, I have this:
<Item></Item>
<Item>
<Id>2276138</Id>
<Title>92907-03100-00 WASHER, CHAIN</Title>
<Link>http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00</Link>
<Price>0.0000</Price>
<Description>WASHER, CHAIN (92907-03100-00)</Description>
<Condition>New</Condition>
<Brand />
<Product_Type />
<Availability>In Stock</Availability>
<Manufacturer>Suzuki</Manufacturer>
</Item>
So after every round of fetching I get the empty item element and just the last element is populated.
Here is the code for the loop:
while (rdr.Read())
{
if (rdr.HasRows)
{
XmlElement part = docOrders.CreateElement("Item");
id.InnerText = rdr[0].ToString();
part.AppendChild(id);
title.InnerText = rdr[1].ToString();
part.AppendChild(title);
link.InnerText = rdr[2].ToString();
part.AppendChild(link);
price.InnerText = rdr[3].ToString();
part.AppendChild(price);
desc.InnerText = rdr[4].ToString();
part.AppendChild(desc);
cond.InnerText = rdr[5].ToString();
part.AppendChild(cond);
brand.InnerText = rdr[6].ToString();
part.AppendChild(brand);
productType.InnerText = rdr[7].ToString();
part.AppendChild(productType);
availability.InnerText = rdr[8].ToString();
part.AppendChild(availability);
manufacturer.InnerText = rdr[9].ToString();
part.AppendChild(manufacturer);
root.AppendChild(part);
}
}
rdr.Close();
}
How Can I solve this, so the data will be fetched correctly?
Thanks in advance
where do you create the id, title, etc. nodes? It looks like you're reusing these instead of creating new nodes, that's why it's not working correctly.
If you're reusing a child node, it will remove it from the current node and insert it into the new node, that's why you're seeing the empty element.
Also check this question here on SO, basically the same exact problem.
You haven't said which version of .NET you are using. If using .NET 3.5 or above, then I would recommend using LINQ to XML, especially if you can get strongly-typed data from your query. For example:
using System;
using System.Linq;
using System.Xml.Linq;
public class Testing
{
private void Main()
{
var items = new[]
{
new DataItem
{
Id = 2276138,
Title = "92907-03100-00 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
new DataItem
{
Id = 2276139,
Title = "92907-03100-01 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
new DataItem
{
Id = 2276140,
Title = "92907-03100-02 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
};
var doc = new XDocument(
new XElement(
"Items",
from item in items
select
new XElement(
"Item",
new XElement("Id", item.Id),
new XElement("Title", item.Title),
new XElement("Link", item.Link),
new XElement("Price", item.Price),
new XElement("Description", item.Description),
new XElement("Condition", item.Condition),
new XElement("Brand", item.Brand),
new XElement("Product_Type", item.ProductType),
new XElement("Availability", item.Availability),
new XElement("Manufacturer", item.Manufacturer))));
}
public class DataItem
{
public int Id { get; set; }
public string Title { get; set; }
public Uri Link { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public string Condition { get; set; }
public string Brand { get; set; }
public string ProductType { get; set; }
public string Availability { get; set; }
public string Manufacturer { get; set; }
}
}
Have you considered using the System.XML.Serialisation namespaces, which has an XMLSerializer class which does this kind of thing very well for you? There's some MSDN documentation here - http://msdn.microsoft.com/en-us/library/swxzdhc0.aspx - which goes into depth with some good examples, and a shorter description here which has enough for the basics - http://support.microsoft.com/kb/815813
Related
Very new to C# and I'm trying to create a list of node data which contains a variable list length of Link data.
class Data
{
public List<Node> Node { get; set; }
}
public class Node
{
public string viewer { get; set; }
public int viewerId { get; set; }
public string log { get; set; }
public List <Link> Link { get; set; }
}
public class Link
{
public string keyName { get; set; }
public int value { get; set; }
}
i have a for loop iterating through the configured nodes and an inner for loop
to grab any configured links.
Data data = new Data();
data.Node = new List<Node>();
I'm doing the following for each new node, which is working how i want it.
data.Node.Add( new Node {
viewer = setup.Device[moduleNr].viewer,
viewerId = setup.Device[moduleNr].viewerId ,
log = setup.Device[moduleNr].log
// how to add one or more lists of Link to this list???
});
The problem i'm having is adding a new list/lists inside the existing data.Node???
Ultimately i would like to achieve the following -
data
|->Node
|->[0]
|->Link
|->[0]
|->keyname
|->value
|->[1]
|->keyname
|->value
|->[2]
|->keyname
|->value
|->log
|->viewerId
|->viewer
|->[1]
|->Link
|->[0]
|->keyname
|->value
|->[1]
|->keyname
|->value
|->log
|->viewerId
|->viewer
|->[2]
|->Link
|->[0]
|->keyname
|->value
|->log
|->viewerId
|->viewer
Would really appreciate some help with this issue - Thanks
You can add a new instance of a List<Link> like this and use the constructor to add new items:
data.Node.Add(new Node {
viewer = setup.Device[moduleNr].viewer,
viewerId = setup.Device[moduleNr].viewerId ,
log = setup.Device[moduleNr].log,
Link = new List<Link>
{
new Link
{
keyName = "Link 1",
value = 0
},
new Link
{
keyName = "Link 2",
value = 1
}
}
});
I am trying to convert a html list to xml format with a console application, but i did what i planned and now i dont know how to continue. I will share my code and explain a bit. What i dont know for now , and is confusing me is where the 'magic' happens. Ok i know i have to take that list from the page , read the list with all the tags inside, but what next, how can i transform that list into xml format? I am new to xml i know some basics so please help me.
Here is the application :
static void Main(string[] args)
{
string _url = "http://example.com/media";
int newsCounter = 0;
List<News> _newsList = new List<News>();
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(_url);
HtmlNode ulNode = doc.DocumentNode.SelectSingleNode("//ul[#class='content articles']");
HtmlNodeCollection liNode = ulNode.SelectNodes(".//li");
foreach (HtmlNode node in ulNode.SelectNodes(".//div[#class='article_box']"))
{
var news = new News();
news.Imgsrc = node.FirstChild.SelectSingleNode("//img").Attributes["src"].Value;
var nodes = doc.DocumentNode.FirstChild.SelectNodes("//img[#src]");
foreach (HtmlNode childNode in node.SelectNodes(".//div[#class='box_info']"))
{
// string src = node.SelectSingleNode("//img").Attributes["src"].Value;
foreach(HtmlNode _node in childNode.SelectNodes(".//h3"))
{
news.Link = "";
news.Title = _node.FirstChild.InnerText;
news.Date = _node.NextSibling.NextSibling.InnerText;
news.Text = _node.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
}
}
_newsList.Add(news);
newsCounter++;
}
and also the News class :
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
}
these are all the parameters i have to read from the list.I am able to read them and return all of the news in my list , but what next , how to transform my list into xml format? Any suggestions are welcomed.
There are many way of creating xml. There are not a lot of items in your case so just using Xml linq is very simple. Putting it into a class may produce cleaner code or you can just use the code directly like Sledge suggested.
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
public XElement ToXml()
{
return new XElement("news", new object[] {
new XElement("Imgscr", Imgsrc),
new XElement("Title", Title),
new XElement("Link", Link),
new XElement("Date", Date),
new XElement("Text", Text),
});
}
}
Thanks to everyone guys. I marked 'News' class as Serializable and with a few lines of code managed to generate the xml file. Here is the code, really simple :
XmlSerializer serializer = new XmlSerializer(typeof(List<News>));
using (TextWriter writer = new StreamWriter(#"D:\News.xml"))
{
serializer.Serialize(writer, _newsList);
}
I'm trying to deserialize simple xml file:
<thesaurus xmlns="http://marklogic.com/xdmp/thesaurus">
<metadata>
</metadata>
<entry>
<term>a</term>
<synonym>
<term>as</term>
</synonym>
</entry>
<entry>
<term>b</term>
<synonym>
<term>bs</term>
</synonym>
<synonym>
<term>bss</term>
</synonym>
</entry>
</thesaurus>
I'm using XmlSerializer like this:
var xmlSerializer = new XmlSerializer(typeof(Thesaurus));
var thesaurus = xmlSerializer.Deserialize(stream);
My model looks like this:
[Serializable]
[XmlRoot("thesaurus", Namespace = "http://marklogic.com/xdmp/thesaurus")]
public class Thesaurus
{
[XmlElement("metadata")]
public Metadata Metadata { get; set; }
[XmlElement("entry")]
public List<Entry> Entries { get; set; }
}
public class Metadata
{
}
public class Entry
{
[XmlElement("term")]
public string Term { get; set; }
[XmlElement("synonym")]
public String[] Synonym { get; set; }
}
So when I'm running this code, I get deserialized thesaurus object with parsed metadata and 1 entry with filled term and synonym fields. I can't get all of the entries here.
BUT
when I comment out Synonym field it starts giving me 2 entries in thesaurus object. I can't wrap entries in <entries> tag because it's some internal format of an application I'm feeding with this xml file.
Anyone has any ideas how to parse this xml file correctly? I tried searching for a solution, but this xml looks quite different than ones in examples.
Ok, so if you need to keep inside synonim field array of terms fields you need to change your Entry class to something like this:
public class Entry
{
[XmlElement("term")]
public string Term { get; set; }
[XmlElement("synonim")]
public Term[] Synonym { get; set; }
}
also you'll need to add additional one:
public class Term
{
[XmlElement("term")]
public string Value { get; set; }
}
This way you'll have what you need.
So, additional hierarchy level was added by additional class.
Please find below code for your test:
var xmlSerializer = new XmlSerializer(typeof(Thesaurus));
var r = new Thesaurus();
r.Entries = new List<Entry>();
r.Metadata = new Metadata();
r.Entries.Add(new Entry()
{
Synonym = new Term[] { new Term(){Value = "1"}, new Term() {Value = "2"}, },
Term = "Term1"
});
r.Entries.Add(new Entry()
{
Synonym = new Term[] { new Term() { Value = "3" }, new Term() { Value = "4" }, },
Term = "Term2"
});
using (TextWriter writer = new StreamWriter(#"c:\111.xml"))
{
xmlSerializer.Serialize(writer, r);
writer.Close();
}
using (TextReader reader = new StreamReader(#"c:\111.xml"))
{
Thesaurus tt = xmlSerializer.Deserialize(reader) as Thesaurus;
Console.Write(tt.Entries.Count);
reader.Close();
}
I am creating an xml using Linq to XML, and the values are in a Product object.
See below c# code snippet generating the xml:
new XElement(xn + "Products",
from p in products
select
new XElement(xn + "Product",
new XElement(xn + "ProductId", p.Id),
new XElement(xn + "Name", p.Name),
new XElement(xn + "Description", new XCData(p.LongDescription.StripHtml())),
new XElement(xn + "CategoryExternalId",
from c in categories
where c.Name == p.PrimaryCategory
select c.CategoryId),
new XElement(xn + "UPCs",
from s in p.SKU
select
new XElement(xn + "UPC", s.UPC))))
));
The challenge is UPCs.
I dont want to create the UPCs xml node if there are no UPC entries in products SKU array.
i.e. p.SKU above in the code snippet, is an array of string UPC fields.
So if not a single UPC field exists i.e. if p.SKU.Count ==0, then I do not want the UPCs xml node elements to be created at all.
See the class model snippet:
public class Product
{
public string Name { get; set; }
public string Description { get; set; }
public List<SKU> SKU { get; set; }
}
public class SKU
{
public string UPC { get; set; }
public string Name { get; set; }
public string Overlap { get; set; }
public string Productline { get; set; }
}
Place that inside your query:
(p.SKU.Count > 0 ?
new XElement("UPCs",
from s in p.SKU
select new XElement( "UPC", s.UPC)) :
null)
I've created a simplified version of your query:
var xml = new XElement("Products",
from p in products
select
new XElement("Product",
new XElement("ProductId", p.Id),
new XElement("Name", p.Name),
(p.SKU.Count > 0 ? new XElement("UPCs",
from s in p.SKU
select new XElement("UPC", s.UPC))
: null)));
And for input like that one:
var products = new List<Product> {
new Product {
Id = 1,
Name = "TestName",
SKU = new List<SKU> {
new SKU { Name = "test", UPC = "UPC1" },
new SKU { Name = "test2", UPC = "UPC2" }
}
},
new Product {
Id = 1,
Name = "TestName",
SKU = new List<SKU> { }
}
};
The output is:
<Products>
<Product>
<ProductId>1</ProductId>
<Name>TestName</Name>
<UPCs>
<UPC>UPC1</UPC>
<UPC>UPC2</UPC>
</UPCs>
</Product>
<Product>
<ProductId>1</ProductId>
<Name>TestName</Name>
</Product>
</Products>
So it's exactly what you're trying to achieve, isn't it?
I have class like this below shown. which contains the shopping items where the number can vary from 0 to n.
namespace SerializationPOC
{
public class ShoppingItems
{
public string CustomerName { get; set; }
public string Address { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string Name { get; set; }
public string Price { get; set; }
}
}
Is it possible to get the class serialized like to get the XML Schema like below.
<?xml version="1.0" encoding="utf-8" ?>
<ShoppingItems>
<CustomerName>John</CustomerName>
<Address>Walstreet,Newyork</Address>
<Item1>Milk</Item1>
<Price1>1$</Price1>
<Item2>IceCream</Item2>
<Price2>1$</Price2>
<Item3>Bread</Item3>
<Price3>1$</Price3>
<Item4>Egg</Item4>
<Price4>1$</Price4>
<Item..n>Egg</Item..n>
<Price..n>1$</Price..n>
</ShoppingItems>
I would like to know if this can be achieved by using the Serilization if not whats the best way to achieve this Schema?
There is no standard serializer that supports that layout. You will have to do it yourself. Personally, I would say "you're doing it wrong"; I strongly suggest (if it is possible) using a format like
<Item name="IceCream" Price="1$"/>
or
<Item><Name>IceCream</Name><Price>1$</Price></Item>
both of which would be trivial with XmlSerializer.
LINQ-to-XML is probably your best option, something like:
var items = new ShoppingItems
{
Address = "Walstreet,Newyork",
CustomerName = "John",
Items = new List<Item>
{
new Item { Name = "Milk", Price = "1$"},
new Item { Name = "IceCream", Price = "1$"},
new Item { Name = "Bread", Price = "1$"},
new Item { Name = "Egg", Price = "1$"}
}
};
var xml = new XElement("ShoppingItems",
new XElement("CustomerName", items.CustomerName),
new XElement("Address", items.Address),
items.Items.Select((item,i)=>
new[] {
new XElement("Item" + (i + 1), item.Name),
new XElement("Price" + (i + 1), item.Price)}))
.ToString();
Can you please have a look on my article, [^]
As an example you can look into the below code. The Serialize method is given on the article.
var test = new ShoppingItems()
{
CustomerName = "test",
Address = "testAddress",
Items = new List<Item>()
{
new Item(){ Name = "item1", Price = "12"},
new Item(){Name = "item2",Price = "14"}
},
};
var xmlData = Serialize(test);
And it will return the string given below,
<?xml version="1.0" encoding="utf-16"?>
<ShoppingItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CustomerName>test</CustomerName>
<Address>testAddress</Address>
<Items>
<Item>
<Name>item1</Name>
<Price>12</Price>
</Item>
<Item>
<Name>item2</Name>
<Price>14</Price>
</Item>
</Items>
</ShoppingItems>