I'm trying to convert a two dimension list of string to an html table.
I did this who does the job :
public string htmlTableFromTwoDimensionList(List<List<string>> list)
{
XDocument xDocument = new XDocument(new XElement("table"));
XElement xTable = xDocument.Element("table");
foreach(List<string> row in list)
{
XElement xRow = new XElement("tr");
foreach(string col in row)
{
if (list.First() == row) xRow.Add(new XElement("th", col));
else xRow.Add(new XElement("td", col));
}
xTable.Add(xRow);
}
return xDocument.ToString();
}
But now, i learn that the string can be some html. So i would like to parse it if it's html or use a string if it's not. I tried to do something like that, without success :
public string htmlTableFromTwoDimensionList(List<List<string>> list)
{
XDocument xDocument = new XDocument(new XElement("table"));
XElement xTable = xDocument.Element("table");
foreach(List<string> row in list)
{
XElement xRow = new XElement("tr");
foreach(string col in row)
{
XElement content;
string text = "";
// tcheck if content is html or text :
try
{
content = XElement.Parse(col);
}
catch
{
text = col;
}
if (list.First() == row) xRow.Add(new XElement("th", string.IsNullOrEmpty(text) ? content : text));
else xRow.Add(new XElement("td", string.IsNullOrEmpty(text) ? content : text));
}
xTable.Add(xRow);
}
return xDocument.ToString();
}
But I'm not even sure to use try catch in this situation. Any idea to do that properly ?
here is a solution, probably not the best, with some sample input :
class Program
{
static void Main(string[] args)
{
List<List<string>> table = new List<List<String>>{
new List<String> { "1d", "Client", "some html", "Date", "col n"},
new List<String> { "1", "Client 1","google","31/12/2022", "some content ..." },
new List<String> { "2", "Client 2","google","31/12/2022", "some content ..." },
new List<String> { "3", "Client 3","google","31/12/2022", "some content ..." },
};
Console.Write(htmlTableFromTwoDimensionList(table));
Console.Read();
}
public static string htmlTableFromTwoDimensionList(List<List<string>> list)
{
XDocument xDocument = new XDocument(new XElement("table"));
XElement xTable = xDocument.Element("table");
foreach (List<string> row in list)
{
XElement xRow = new XElement("tr");
foreach (string col in row)
{
XElement htmlCel;
if (list.First() == row) htmlCel = new XElement("th");
else htmlCel = new XElement("td");
XElement content;
try
{
content = XElement.Parse(col);
htmlCel.Add(content);
}
catch
{
htmlCel.Add(col);
}
xRow.Add(htmlCel);
}
xTable.Add(xRow);
}
return xDocument.ToString();
}
}
Related
Im working on getting some values from an RSS feed but i am having difficulties getting a value which has the namespace in the element tag. I've tried adding the namespace to the lookup of the value but i always get null
Any idea on how this is achieved?
Feed
https://wegotthiscovered.com/movies/feed/
Element
xmlns:content="http://purl.org/rss/1.0/modules/content/"
Namespace
content:encoded
public async Task<bool> GetNewsFeeds()
{
Database db = new Database();
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("https://wegotthiscovered.com/movies/feed/", "Movie");
dictionary.Add("https://wegotthiscovered.com/blu-ray/feed/", "Blu-ray");
dictionary.Add("https://wegotthiscovered.com/reviews/feed/", "Reviews");
dictionary.Add("https://wegotthiscovered.com/featured/feed/", "Featured");
dictionary.Add("https://wegotthiscovered.com/galleries/feed/", "Galleries");
db.DeletMovieNews();
foreach (var pair in dictionary.ToList())
{
try
{
if (PhysicalDevice.HasInternetConnection())
{
XDocument doc = XDocument.Load(pair.Key);
XNamespace nsSys = "http://purl.org/rss/1.0/modules/content/";
var entries = (from item in doc.Descendants("item")
select new Movie_News
{
Content = item.Element(nsSys + "encoded").Value, // ISSUE HERE
Link = item.Element("link").Value,
PublishedDate = item.Element("pubDate").Value,
Title = item.Element("title").Value,
Description = item.Element("description").Value,
GroupName = "News",
FeedName = pair.Value
});
List<Movie_News> newsCollection = entries.ToList();
if (newsCollection.Count() != 0)
{
using (var rateGate = new RateGate(40, TimeSpan.FromSeconds(10)))
{
rateGate.WaitToProceed();
foreach (Movie_News item in newsCollection)
{
string regex = #"((http|ftp|https):\/\/)?([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,#?^=%&:\/~+#-]*[\w#?^=%&\/~+#-])?";
Match match = Regex.Match(item.Description, regex);
if (match.Success)
{
item.ImageUrl = match.Value;
item.B64Image = await DownloadImage(item.ImageUrl);
}
item.Description = item.Description.Remove(0, item.Description.IndexOf("</div>"));
item.Description = item.Description.Replace("</div>","");
db.InsertNewsData(item);
}
}
}
return true;
}
}
catch(Exception ex)
{
return false;
}
}
return true;
}
}
Typical , soon as i completed the write up, its working now
Im working with HtmlAgilityPack in C# and im presented with plain p-tagless text.
I've already wrote an extension that lets me add p tags around p-tagless text, but when i get text<i>foo</i>text in the p-tagless text, it turns into <p>text</p><i><p>foo</p></i><p>text</p>.
How do i convert this:
text<i>another piece of text</i>text
into this:
<p>text<i>another piece of text</i>text</p>
here is my extension:
private static readonly string[] unacceptableParents = { "p", "a", "i", "h2", "h3", "h4", "h5", "h6" };`
public static HtmlDocument AddPTagAroundTextWithoutTag(this HtmlDocument doc)
{
GetXPathOfText(doc, doc.DocumentNode);
return doc;
}
public static void AddPTags(HtmlDocument doc, HtmlNode node)
{
var tekstName = "#text";
if (node.HasChildNodes)
{
foreach (var thisNode in node.ChildNodes)
{
if (thisNode.ChildNodes.Any())
{
GetXPathOfText(doc, thisNode);
}
else if (thisNode.Name == tekstName && !unacceptableParents.Contains(thisNode.ParentNode.Name))
{
thisNode.Name = "p";
thisNode.InnerHtml = "<p>" + node.InnerText.Trim() + "</p>";
}
}
}
else
{
if (node.Name == tekstName && !unacceptableParents.Contains(node.ParentNode.Name))
{
node.Name = "p";
node.InnerHtml = "<p>" + node.InnerText.Trim() + "</p>";
}
}
}
Firstly, I read heaps of topics about JSON to TreeView on the Stackoverflow. After this, I create a JSON data like this:
{
"Cars": {
"Audi": [{
"A6 2.0 TDI quatro 2018 Red": ["S-Line", "17 inch rim", "Full sport packet"],
"A5 1.6 TFSI 2018 Blue": ["Desing packet", "Sunroof"]
}],
"Mercedes-Benz": [{
"E220d AMG 2018 white": ["Glass ceiling", "Vacuum doors", "Navigation"],
"E220d Exclusive Black 2018 Blue": ["Power seats", "Start & Stop"]
}]
}
}
Here is the C# code content:
private void Form1_Load(object sender, EventArgs e)
{
try
{
treeView1.Nodes.Clear();
var json = File.ReadAllText(Uz.path + #"cars.json");
var obj = JObject.Parse(json);
var parent = Json2Tree(obj);
treeView1.Nodes.Add(parent);
treeView1.ExpandAll();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"ERROR");
}
}
private static TreeNode Json2Tree(JObject obj)
{
//create the parent node
var parent = new TreeNode();
//loop through the obj. all token should be pair<key, value>
foreach (var token in obj)
{
//change the display Content of the parent
parent.Text = token.Key;
//create the child node
var child = new TreeNode();
child.Text = token.Key;
//check if the value is of type obj recall the method
if (token.Value.Type.ToString() == "Object")
{
// child.Text = token.Key.ToString();
//create a new JObject using the the Token.value
var o = (JObject)token.Value;
//recall the method
child = Json2Tree(o);
//add the child to the parentNode
parent.Nodes.Add(child);
}
//if type is of array
else if (token.Value.Type.ToString() == "Array")
{
int ix = -1;
// child.Text = token.Key.ToString();
//loop though the array
foreach (var itm in token.Value)
{
//check if value is an Array of objects
if (itm.Type.ToString() == "Object")
{
//child.Text = token.Key.ToString();
//call back the method
ix++;
var o = (JObject)itm;
var objTN = Json2Tree(o);
//objTN.Text = token.Key + "[" + ix + "]";
child.Nodes.Add(objTN);
//parent.Nodes.Add(child);
}
//regular array string, int, etc
else if (itm.Type.ToString() == "Array")
{
ix++;
var dataArray = new TreeNode();
foreach (var data in itm)
{
//dataArray.Text = token.Key + "[" + ix + "]";
dataArray.Nodes.Add(data.ToString());
}
child.Nodes.Add(dataArray);
}
else
{
child.Nodes.Add(itm.ToString());
}
}
parent.Nodes.Add(child);
}
else
{
//if token.Value is not nested
// child.Text = token.Key.ToString();
//change the value into N/A if value == null or an empty string
child.Nodes.Add(token.Value.ToString() == "" ? "N/A" : token.Value.ToString());
parent.Nodes.Add(child);
}
}
return parent;
}
when I run the code, the screenshot looks like this:
But marked as 1, 2 and 3 are should not be shown. It must be like this:
Although I worked 3 days, I did not succeed.
In JsonTreeView project, it show like this:
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
namespace JsonTreeView
{
public static class JsonToTreeView
{
public static void Json2Tree(this TreeView treeView, string json, string group_name)
{
if (string.IsNullOrWhiteSpace(json))
{
return;
}
var obj = JObject.Parse(json);
AddObjectNodes(obj, group_name, treeView.Nodes);
}
public static void AddObjectNodes(JObject obj, string name, TreeNodeCollection parent)
{
var node = new TreeNode(name);
parent.Add(node);
foreach (var property in obj.Properties())
{
AddTokenNodes(property.Value, property.Name, node.Nodes);
}
}
private static void AddArrayNodes(JArray array, string name, TreeNodeCollection parent)
{
var node = new TreeNode(name);
parent.Add(node);
for (var i = 0; i < array.Count; i++)
{
AddTokenNodes(array[i], $"[{i}]", node.Nodes);
}
}
private static void AddTokenNodes(JToken token, string name, TreeNodeCollection parent)
{
switch (token)
{
case JValue _:
parent.Add(new TreeNode($"{((JValue) token).Value}"));
break;
case JArray _:
AddArrayNodes((JArray)token, name, parent);
break;
case JObject _:
AddObjectNodes((JObject)token, name, parent);
break;
}
}
}
}
I'm looking for a easy way to convert my xml to json with the additional option to add the full xpath as attribute. Now I do it this way:
private static string XmlToJson(string xmlString)
{
return new JavaScriptSerializer().Serialize(GetXmlValues(XElement.Parse(xmlString)));
}
private static Dictionary<string, object> GetXmlValues(XElement xml)
{
var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
if (xml.HasElements)
{
attr.Add("_children", xml.Elements().Select(e => GetXmlValues(e)));
attr.Add("_path", xml.GetPath());
}
else if (!xml.IsEmpty)
{
attr.Add("_value", xml.Value);
attr.Add("_path", xml.GetPath());
}
return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}
private static string GetPath(this XElement node)
{
string path = node.Name.LocalName;
XElement currentNode = node;
while (currentNode.Parent != null)
{
currentNode = currentNode.Parent;
path = currentNode.Name.LocalName + "/" + path;
}
return path;
}
But it looks circuitous compare to:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
But there for I have no idea how to add the path during the convertion?
But it looks circuitous compare to
Json.net uses it's own implementation of JsonConverter named XmlNodeConverter. So if you want it to look not circuitous, you can implement your own JsonConverter and use it:
var doc = XDocument.Parse(xml);
var json = JsonConvert.SerializeObject(doc, new MyXmlWithXPathJsonConverter());
This is a nice but quite complex task.
But a bit simpler way is to append your xml nodes with xpath attribute right before serialization. For example:
public void AppendXPath(XContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
var doc = container as XDocument;
if (doc != null)
AppendXPath(doc.Root, "", 1);
else
AppendXPath(container as XElement, "/", 1);
}
private void AppendXPath(XElement node, string parent, int num)
{
var path = $"{parent}/{node.Name}[{num}]";
if (node.Attribute("xpath") != null)
throw new InvalidOperationException($"Node {path} already contains xpath attribute");
var indicies = new Dictionary<XName, int>();
foreach (var child in node.Elements())
{
int index;
if (indicies.TryGetValue(child.Name, out index))
indicies[child.Name] = ++index;
else
indicies[child.Name] = index = 1;
AppendXPath(child, path, index);
}
node.Add(new XAttribute("xpath", path));
}
Test:
void Test()
{
var xml =
#"<xml>
<foo>
<one />
<other />
</foo>
<bar data=""abc"">
<item order=""3"" />
<item order=""1"">
<child whatever="""" />
</item>
</bar>
</xml>";
var doc = XDocument.Parse(xml);
AppendXPath(doc);
var json = JsonConvert.SerializeObject(doc, Newtonsoft.Json.Formatting.Indented);
Console.WriteLine(json);
}
Result:
{
"xml": {
"#xpath": "/xml[1]",
"foo": {
"#xpath": "/xml[1]/foo[1]",
"one": {
"#xpath": "/xml[1]/foo[1]/one[1]"
},
"other": {
"#xpath": "/xml[1]/foo[1]/other[1]"
}
},
"bar": {
"#data": "abc",
"#xpath": "/xml[1]/bar[1]",
"item": [
{
"#order": "3",
"#xpath": "/xml[1]/bar[1]/item[1]"
},
{
"#order": "1",
"#xpath": "/xml[1]/bar[1]/item[2]",
"child": {
"#whatever": "",
"#xpath": "/xml[1]/bar[1]/item[2]/child[1]"
}
}
]
}
}
}
I am trying to write music Tags into an XML, but it fails on invalid chars, I have tried doing a replace but I can't seem to get the syntex right.
//string pattern = "[\\~#%&*{}/:<>?|\"-]";
//string replacement = "_";
//Regex regEx = new Regex(pattern);
//string sanitized = Regex.Replace(regEx.Replace(input, replacement), #"\s+", " ");
XDocument baddoc = new XDocument
(new XElement("Corrupt",
badfiles.Select(badfile =>
new XElement("File", badfile))));
baddoc.Save("D:\\badfiles.xml");
// foreach(string musicfile in musicfiles)
//{ String Title = (TagLib.File.Create(musicfile).Tag.Title); }
XDocument doc = new XDocument
(new XElement("Songs",
musicfiles.Select(musicfile=>
new XElement("Song",
(new XElement("Title", (TagLib.File.Create(musicfile).Tag.Title))),
(new XElement("Path", (musicfile))),
(new XElement("Artist", (TagLib.File.Create(musicfile).Tag.Performers)))
))));
doc.Save("D:\\files.xml");
I ended up breaking it all out like this:
XDocument doc = new XDocument();
XElement songsElement = new XElement("Songs");
foreach(var musicfile in musicfiles)
{
XElement songElement = new XElement("Song");
string songTitle;
try { songTitle = (TagLib.File.Create(musicfile).Tag.Title); }
catch { songTitle = "Missing"; }
uint songTNint;
try { songTNint = (TagLib.File.Create(musicfile).Tag.Track); }
catch { songTNint = 00; }
string songTN = songTNint.ToString();
string songPath = musicfile;
string songArtist;
try {songArtist = (TagLib.File.Create(musicfile).Tag.Performers[0]);}
catch {songArtist = "Missing";}
List<string> songGenres = new List<string>();
foreach (string Genre in (TagLib.File.Create(musicfile).Tag.Genres))
{ songGenres.Add(Genre);}
string songGenre;
if (songGenres.Count > 1) { songGenre = (songGenres[0] + "/" + songGenres[1]); }
else { try { songGenre = songGenres[0]; } catch { songGenre = "Missing"; } }
songArtist = Regex.Replace(songArtist, #"[^\u0020-\u007E]", string.Empty);
XElement titleElement = new XElement("Title",songTitle);
XElement tnElement = new XElement("TN", songTN);
XElement pathElement = new XElement("Path", musicfile);
XElement artistElement = new XElement("Artist",songArtist);
XElement genreElement = new XElement("Genre", songGenre);
songElement.Add(titleElement);
songElement.Add(tnElement);
songElement.Add(pathElement);
songElement.Add(artistElement);
songElement.Add(genreElement);
songsElement.Add(songElement);
}