Convert a list of objects to an xml string - c#

Hello I have a list of object i want to convert into an xml. Here is what the final xml should look like.
<ArrayOfTweet>
<Tweet>
<Photos>
<Photo>
<PhotoHeight>FOO</PhotoHeight>
<PhotoUri>a/random/ur/path</PhotoUri>
<PhotoWidth>923</PhotoWidth>
<SourcePhotoUri>a/random/path</SourcePhotoUri>
</Photo>
</Photos>
<ProfileImage>a/random/path</ProfileImage>
<ScreenName>FOO</ScreenName>
<Text>some text</Text>
<TweetId>1234</TweetId>
<UserId>1234</UserId>
<Username>BAR</Username>
</Tweet>
<Tweet>
<Photos>
<Photo>
<PhotoHeight>FOO</PhotoHeight>
<PhotoUri>a/random/ur/path</PhotoUri>
<PhotoWidth>923</PhotoWidth>
<SourcePhotoUri>a/random/path</SourcePhotoUri>
</Photo>
</Photos>
<ProfileImage>a/random/path</ProfileImage>
<ScreenName>FOO</ScreenName>
<Text>some text</Text>
<TweetId>1234</TweetId>
<UserId>1234</UserId>
<Username>BAR</Username>
</Tweet>
</ArrayOfTweet>
I have converted each of the objects in the list into an xml string like so
//TweetList is the list of tweet objects
List<string> xmlStringTweetList = new List<string>();
foreach (var tl in TweetList)
{
xmlStringTweetList.Add(toXML(tl));
}
private string toXML(Tweet t)
{
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(t.GetType());
serializer.Serialize(stringwriter, t);
return stringwriter.ToString();
}
I tried converting that list into the format above using
XElement xmlElements = new XElement("ArrayOfTweet", xmlStringTweetList.Select(i => new XElement("Tweet", i)));
But there is the extra <Tweet></Tweet> That i dont need. Is there a way of doing this?

I made a fiddle here that illustrates a way to serialize your object all at once, instead of piecing strings together.
I suspect your extra <Tweet></Tweet> is because of a null or empty value in the list, because I am not experiencing it in my test above.

I think XElement xmlElements = new XElement("ArrayOfTweet", xmlStringTweetList.Select(i => XElement.Parse(i))); should do.

Related

Extract Inner Nodes from XML string to a JSON string

string inputxml = "<transaction>
<node1>value1</node1>
<node2>value2</node2>
<node3>value3</node3>
</transaction>"
I want to convert this XML string to JSON string in the below format after omitting the outermost node:
{"node1";"value1","node2":"value2","node3":"value3"}
You can use :
1 - XDocument to build anonymous object that match the Json like :
string inputxml = #"<transaction>
<node1>value1</node1>
<node2>value2</node2>
<node3>value3</node3>
</transaction>";
var node = XDocument.Parse(inputxml)
.Descendants("transaction")
.Select(x => new
{
Node1 = x.Element("node1").Value,
Node2 = x.Element("node2").Value,
Node3 = x.Element("node3").Value
}).FirstOrDefault();
2 - Newtonsoft to serialize the object like :
string json = JsonConvert.SerializeObject(node);
Demo
Console.WriteLine(json);
Result
{"Node1":"value1","Node2":"value2","Node3":"value3"}
I hope you find this helpful.
As far as i understood your problem you do not have model neither for source XML nor for JSON and names can chenge in future, so we shouldn't use strict names. So we will try to build it dynamically. Pay attention - u'll need to use Newtonsoft.Json nuget pack.
string inputxml = #"<transaction>
<node1>value1</node1>
<node2>value2</node2>
<node3>value3</node3>
</transaction>";
XDocument xdoc = XDocument.Parse(inputxml); //parse XML document
var jprops = xdoc.Root.Elements() // take elements in root of the doc
.Select(x => (x.Name, x.Value)) // map it to tuples (XName, string)
.Select(x => new JProperty(x.Name.LocalName, x.Value)); //map it to enumerbale of Json properties
JObject resultingObj = new JObject(jprops); // construct your json and populate its contents
Console.WriteLine(resultingObj.ToString()); // Write out - u r awesome

XMLinvalide chars replacement C#

I have a string that is displayed in XML but in it I have some invalid chars like string
s = <root> something here <XMLElement>hello</XMLElement> somethig here too </root>
where XMLElement is a List like XMLElement = {"bold", "italic",...} .
What I need is to replace the < and </ if followed by any of the XMLElements to be replaced by > or < depending on the cases.
The <root> is to keep
I have tried so far some regEx
strAux = Regex.Replace(strAux, "bold=\"[^\"]*\"",
match => match.Value.Replace("<", "<").Replace(">", ">"));
or
List<string> startsWith = new List<string> { "<", "</"};
foreach(var stw in startsWith)
{
int nextLt = 0;
while ((nextLt = strAux.IndexOf(stw, nextLt)) != -1)
{
bool isMatch = strAux.Substring(nextLt + 1).StartsWith(BoldElement); // needs to ckeck all the XMLElements
//is element, leave it
if (isMatch)
{
//its not, replace
strAux = string.Format(#"{0}<{1}", strAux.Substring(0, nextLt), strAux.Substring(nextLt +1, strAux.Length - (nextLt + 1)));
}
nextLt++;
}
}
Also tried
XmlDocument doc = new XmlDocument();
XmlElement element = doc.CreateElement("root");
element.InnerText = strAux;
Console.WriteLine(element.OuterXml);
strAux = element.OuterXml.Replace("<root>", "").Replace("</root>", "");
return strAux; But it will repeat the `<root>` too
But nothing worked like I suposed. Is there any different ideias .Thanks
What you have is well-formed XML, so you can use the XML APIs to help you:
Using LINQ to XML (which is generally the better API):
var element = XElement.Parse(s);
element.Value = string.Concat(element.Nodes());
var result = element.ToString();
Or using the older XmlDocument API:
var doc = new XmlDocument();
doc.LoadXml(s);
var root = doc.DocumentElement;
root.InnerText = root.InnerXml;
var result = root.OuterXml;
The result for both is:
<root> something here <XMLElement>hello</XMLElement> somethig here too </root>
See this fiddle for a demo.
You should be using the XmlWriter class.
Sample from the documentation:
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.CloseOutput = false;
// Create the XmlWriter object and write some content.
MemoryStream strm = new MemoryStream();
XmlWriter writer = XmlWriter.Create(strm, settings);
writer.WriteElementString("someNode", "someValue");
writer.Flush();
writer.Close();
https://msdn.microsoft.com/en-us/library/system.xml.xmlwriter(v=vs.110).aspx
It sounds like your input is well-formed XML, but you want to escape some of the tags. The issue here is that there's no way for the code to know which tags are valid and which aren't.
One way to do this is to create a list of valid tags.
List<string> validTags = new List<string>() { "root", "..." };
Then use regex to pick out all instances of <tag> or </tag>and replace them if they're not in the list.
Another way which is faster and easier, but requires more information up front, is to create a list of tags which aren't valid.
List<string> invalidTags = new List<string>() { "XMLElement", "..." };
Simple string manipulation will do, now.
string s = GetYourXMLString();
invalidTags.ForEach(t => s = s.Replace($"</{t}>",$"<{t}>")
.Replace($"<{t}>",$"</{t}>"));
The second way should really only be used if you know which foreign tags are making (or will ever make) an appearance. If not the first approach should be used. One clever possibility is to dynamically create the list of valid tags using reflection or a data contract so that changes to the XML spec will be automatically reflected in your code.
For example, if each element is a property of an object, you might get the list like this:
var validTags = typeof(MyObjectType).GetProperties()
.Select(p => p.PropertyName)
.ToList();
Of course, the property names likely won't be the actual tag names, AND often you'll want to only include certain properties. So you make an attribute class to designate the desired properties (let's call it XMLTagName) and then you can do this:
var validTags = typeof(MyObjectType).GetProperties()
.Select(p => p.GetCustomAttribute<XMLTagName>()?.TagName)
.Where(tagName => tagName != null) //gets rid of properties that aren't tagged
.ToList();
Even with all that, you'll still committing the crime of string manipulation on raw XML. After all, the best real solution here is to figure out how to fix the incoming XML to actually contain the data you want. But if that's not a possibility, the above should do the job.

Linq to XML data structure

This is my XML:
<home>
<contents>
<row>
<content>
<idContent>1</idContent>
<title>title1</title>
</content>
<content>
<idContent>2</idContent>
<title>title2</title>
</content>
</row>
<row>
<content>
<idContent>3</idContent>
<title>title3</title>
</content>
<content>
<idContent>4</idContent>
<title>title4</title>
</content>
</row>
</contents>
I want to store this information in a list of objects
List myList = ...
Where a Content could be:
int idContent;
string title;
int row_number;
Each Content object has to store the row where it is located in the XML.
What's the best way for doing this?
Presuming row_number is simply a sequence relating to the order it appears in the XML, then you can do something like this:
var doc = XDocument.Parse(xml);
var contents = doc.Descendants("row")
.Select((e, index) => new {Row = e, RowIndex = index})
.SelectMany(x => x.Row.Elements("content").Select(e => new {Content = e, x.RowIndex}))
.Select(x => new Content
{
IdContent = (int)x.Content.Element("idContent"),
Title = (string)x.Content.Element("title"),
RowNumber = x.RowIndex + 1
}).ToList();
I use this method for similar scenarios:
public static Object CreateObject(string XMLString, Object YourClassObject)
{
System.Xml.Serialization.XmlSerializer oXmlSerializer = new System.Xml.Serialization.XmlSerializer(YourClassObject.GetType());
//The StringReader will be the stream holder for the existing XML file
YourClassObject = oXmlSerializer.Deserialize(new System.IO.StringReader(XMLString));
//initially deserialized, the data is represented by an object without a defined type
return YourClassObject;
}
With this method you can create a class object from a XML String. I haven't tested it on your scenario, but you can use it on object of following home class:
public class home
{
public List<row> contents;
}
public class row
{
public List<content> content;
}
public class content
{
public int idContent;
public string title;
}
USAGE:
home h = new home();
h = (home)CreateObject(xml, h);
Remember that the variable and class names must be exactly same as that of XML nodes.
EXTRA:
If you want to convert a class object into XML String, use this method:
string CreateXML(Object YourClassObject)
{
XmlDocument xmlDoc = new XmlDocument(); //Represents an XML document,
// Initializes a new instance of the XmlDocument class.
XmlSerializer xmlSerializer = new XmlSerializer(YourClassObject.GetType());
// Creates a stream whose backing store is memory.
using (MemoryStream xmlStream = new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, YourClassObject);
xmlStream.Position = 0;
//Loads the XML document from the specified string.
xmlDoc.Load(xmlStream);
return xmlDoc.InnerXml;
}
}
The best solution I could think of - although it is not using Linq to XML - is to feed your XML document into one of those various XML Schema generators like http://www.freeformatter.com/xsd-generator.html and pipe this generated Schema right into xsd.exe (see https://msdn.microsoft.com/en-us/library/x6c1kb0s.aspx). The generated code can be used to read (and write) the XML document such as the one you provided and you can of course apply Linq to Objects on this collection.
However, since you mentioned the row_number field which does not yet appear in your example XML, you would have to add this to the XML or manually edit the XML Schema afterwards.

Dictionary to XML

So, I have the following function that takes in a Dictionary of Users and ControlNumbers and outputs it to XML. Found some LINQ online that did this very well; but I have one small problem.
static Dictionary<string, User> UserClassDict = new Dictionary<string, User>();
static void DictionaryToXML(Dictionary<string,User> UserClassDict)
{
XElement el = new XElement("root", UserClassDict.Select(kv => new XElement(kv.Key, kv.Value.ControlNumber
)));
}
The XML looks like this:
<root>
<adolan>792365</adolan>
<afeazell>791964</afeazell>
<amsmith>790848</amsmith>
<asnyder>790948789358</asnyder>
</root>
But as you can see, the ControlNumbers are generally 6 digits long (HOWEVER this is not always the case). What I would like to happen is something similar to this.
<root>
<adolan>
<controlNumbers>123456</controlNumbers>
</adolan>
<asnyder>
<controlNumbers>222111</controlNumbers>
<controlNumbers>333222</controlNumbers>
</asnyder>
</root>
Eventually I will have the program read this XML file at start up and populate the Dictionary so this XML will eventually get pretty large. Any ideas would be helpful.
Try this
XElement el = new XElement("root",
UserClassDict.Select(kv => new XElement(kv.Key,
kv.Value.ControlNumbers.Select(num => new XElement("controlNumbers", num))))
);
I don't fully understand how 2 or more control numbers are represented in your dictionary, but if you want to do some more complex xlm generation, you can change your lambda so that it invokes a method.
kv => new XElement(kv.Key, kv.Value.ControlNumber)
would change to
kv => BuildXMLElement(kv)
and you can implement BuildXMLElement to build the element as you like
Change your el to
XElement el = new XElement("root", UserClassDict.
Select(kv => new XElement(kv.Key,
from it in kv.Value.ControlNumber
select new XElement("controlNumbers", it)
)));
The above LINQ query will create multiple controlNumbers tags
To concatenate, use
XElement el = new XElement("root", UserClassDict.
Select(kv => new XElement(kv.Key,
String.Join(",", kv.Value.ControlNumber.ToArray())
)));

Deserialize <table> nodes to double[][] from XML

I have an XML file (from somewhere) containing matrix values, which I wish to get into my code as double[][] objects. The XML contains table nodes, which look like standard serialized double[][] objects:
<table type="System.Double[][]"><table type="System.Double[]"><el type="System.Double">0.005</el><el type="System.Double">0.001</el><el type="System.Double">0.007</el><el type="System.Double">-0.012</el></table><table type="System.Double[]"><el type="System.Double">0.033</el><el type="System.Double">-0.146</el><el type="System.Double">-0.008</el><el type="System.Double">0.006</el></table><table type="System.Double[]"><el type="System.Double">-0.002</el><el type="System.Double">-0.004</el><el type="System.Double">-0.004</el><el type="System.Double">-0.003</el></table><table type="System.Double[]"><el type="System.Double">0</el><el type="System.Double">0</el><el type="System.Double">0</el><el type="System.Double">0</el></table></table>
Since not the whole XML is in this form, I only extract those nodes as XmlNode (since XElements don't have InnerXml). Lets call this myMatrixXmlNode.
Then, I try to put that into a MemoryStream, and then deserialize from that:
var deserializer = new XmlSerializer(typeof(double[][]));
var myMatrix = (double[][])deserializer.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(myMatrixXmlNode.InnerXml)));
This throws me a <table xmlns=''> was not expected. error, for which I have not found a solution yet.. and I'm geting really annoyed by this.
Probably best to use an XDocument to parse it like the following:-
var d = XDocument.Parse(testXml);
var r = d.Element("table");
var listOfDoubleArrays = new List<double[]>();
foreach (var outerArrayItem in r.Elements())
{
double[] arr = new double[r.Elements().Count()];
int i = 0;
foreach (var innerArrayItem in outerArrayItem.Elements())
{
arr[i] = System.Convert.ToDouble(innerArrayItem.Value);
i++;
}
listOfDoubleArrays.Add(arr);
}
double[][] result = listOfDoubleArrays.ToArray();
You can not use standart Xml serializer for deserializing this Xml into double[][].
Format for double[][] Xml serialization is like:
<ArrayOfArrayOfDouble xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<ArrayOfDouble>
<double>1</double>
</ArrayOfDouble>
<ArrayOfDouble>
<double>2</double>
</ArrayOfDouble>
</ArrayOfArrayOfDouble>
You can try parse thos Xml manually using LinqToXml or transforming it to corresponding format.

Categories

Resources