C# XDocument right way to escape symbols - c#

Hello I'm struggling with escaping in xml, problem is my output is escaped 2 times and I dont understand why its happening.
Code below:
private static string FixSingleEncoding(string data)
{
//data?.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(""", """).Replace("'", "&apos;");
return System.Net.WebUtility.HtmlEncode(data); //SecurityElement.Escape(data);//
}
private static XDocument FixEncoding(XDocument instance)
{
XNamespace naming = instance.Root.Name.Namespace;
var result = instance.Descendants(naming + "dataset").ToList();
var count = result.Count;
for (int i = 0; i < count; i++)
{
result[i].Value = FixSingleEncoding(result[i].Value);
}
return instance;
}
public static bool CreateNewDataset(string path, string data)
{
Debug.WriteLine("CALL");
XDocument xdoc = XDocument.Load(Path.Combine(MasterLocation, path));
xdoc = FixEncoding(xdoc);
XNamespace df = xdoc.Root.Name.Namespace;
XElement root = new XElement(df+"changeSet");
root.Add(new XAttribute("id", "My Name"));
root.Add(new XAttribute("author", "Test"));
string final = data;
XElement innerelement = new XElement(df + "data", final);
innerelement.Add(new XAttribute("endDelimiter", "GO"));
root.Add(innerelement);
xdoc.Root.Add(root);
xdoc.Save(Path.Combine(MasterLocation, path));
return true;
}
Problem is when I first time load xml file and use method CreateNewDataset it retrieves all data from xml file and unescape old data, so I put FixEncoding method, but then another problem showed up, now it escapes two times, how do I know that exactly two times, well using VS Code and converting XML Entity to string, it needs to converted 2 times to readable string, CreateNewDataset method is called only once, but data escaped two times, what do I miss here?
entered data
IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = object_id(N'[dbo].[table1]')
and OBJECTPROPERTY(id, N'IsProcedure') = 0)
orginal code before CreateNewDataset:
<changeSet id="Test" author="My Name">
<data endDelimiter="GO">
IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = object_id(N&apos;[dbo].[table1]&apos;)
and OBJECTPROPERTY(id, N&apos;IsProcedure&apos;) = 0)
</data>
</changeSet>
AFTER createnewdataset(without FixEncoding)
<changeSet id="Test" author="My Name">
<data endDelimiter="GO">
IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = object_id(N'[dbo].[table1]')
and OBJECTPROPERTY(id, N'IsProcedure') = 0)
</data>
</changeSet>

Related

C# (Xamarin): looping through XML

I have a Xamarin (C#) project, where I am trying to loop through some XML, but for some reason my code is not working.
This is what I have now:
DeviceList = new List<DeviceInfo>();
string ResultStatus = "";
string ResultDevice = "";
var result = Encoding.Default.GetString(e.Result);
result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + result;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(result);
string xPathStatus = "ed_listdevices";
var nodes = xmlDoc.SelectNodes(xPathStatus);
foreach (XmlNode xNode in nodes) {
ResultStatus = xNode.SelectSingleNode("//status").InnerText;
ResultDevice = xNode.SelectSingleNode("//device").InnerText;
}
if (ResultStatus.ToLower() == "ok") {
XmlDocument deviceDoc = new XmlDocument();
deviceDoc.LoadXml(result);
var deviceNodes = deviceDoc.SelectNodes(xPathStatus + "/device");
//foreach(XmlNode dNode in deviceNodes) {
for (int i = 0; i < deviceNodes.Count; i++) {
DeviceList.Add(new DeviceInfo() {
DeviceID = deviceNodes[i].SelectSingleNode("//id").InnerXml,
DeviceName = deviceNodes[i].SelectSingleNode("//name").InnerXml,
DeviceExtraName = "",
DeviceOnlineStatus = deviceNodes[i].SelectSingleNode("//status").InnerXml,
Location = deviceNodes[i].SelectSingleNode("//address").InnerXml,
Time = deviceNodes[i].SelectSingleNode("//time").InnerXml
});
}
}
When I step though the code I get the "ResultStatus" and "ResultDevice" correctly, and when I get to the
for (int i = 0; i < deviceNodes.Count; i++)
the "deviceNodes" variable have a count of 91, and I can see all the individual xml elements that I am suppose to get from the webservice I am calling.
However, when I loop through deviceNodes[i] I only get values from the very first XML element (yes, the value of "i" does change). In other words, my DeviceList is filled with 91 entries with the same values.
Am I missing something obvious?? What am I doing wrong since this isn't working??
PS: I have also tried using a foreach (XmlNode node in deviceNodes) but the result was the same.
"//" in the selector tells it to search from the root node of the document. If you want to search locally under the "current" node, remove the "//"

XmlDocument sort nodes by the inner text value of a child

i want to sort the nodes called ImageInfo by the number in the pos node because i have buttons that change the position up or down and i need to sort the ImageInfo node in the correct order when the pos has changed.
i apologise ahead for not having any c# code but i assure you that i have tried so many different things and im in need of help.
here is my xml:
<?xml version="1.0" encoding="utf-8"?>
<MplAndSiImages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MplImages>
<ImageInfo>
<pos>1</pos>
<Name>1.png</Name>
<ParentObjectId>b66a23a8-6268-e611-80e2-c4346bad02e8</ParentObjectId>
<Url>http://localhost:8080/b66a23a8-6268-e611-80e2-c4346bad02e8/1.png</Url>
</ImageInfo>
<ImageInfo>
<pos>2</pos>
<Name>2.png</Name>
<ParentObjectId>b66a23a8-6268-e611-80e2-c4346bad02e8</ParentObjectId>
<Url>http://localhost:8080/b66a23a8-6268-e611-80e2-c4346bad02e8/2.png</Url>
</ImageInfo>
<ImageInfo>
<pos>3</pos>
<Name>3.png</Name>
<ParentObjectId>b66a23a8-6268-e611-80e2-c4346bad02e8</ParentObjectId>
<Url>http://localhost:8080/b66a23a8-6268-e611-80e2-c4346bad02e8/3.png</Url>
</ImageInfo>
</MplImages>
<SiImages />
</MplAndSiImages>
here is my c# code:
it is called on the click of an action link button and i need it to change the poition to 1 less to move it up in the list and i have the number change but the xml need s to be sorted so it has the ImageInfo nodes in the correct order.
public ActionResult MoveUp(string name, string id)
{
var pathConfig = WebConfigurationManager.AppSettings["ProductImageFolderPath"];
var url = pathConfig + id + "\\" + "ModelConfig.xml";
XmlDocument doc = new XmlDocument();
doc.Load(url);
XmlNode root = doc.DocumentElement;
XmlNode upNode = root.SelectSingleNode("/MplAndSiImages/MplImages/ImageInfo[Name/text() = '" + name + "']/pos");
string upNodeValue = upNode.InnerText;
int upNodeInt = Int32.Parse(upNodeValue);
upNodeInt = upNodeInt - 1;
var upNodeString = upNodeInt.ToString();
upNode.InnerText = upNodeString;
XmlNode downNode = root.SelectSingleNode("/MplAndSiImages/MplImages/ImageInfo/pos[text() = '" + upNodeString + "']");
string downNodeValue = downNode.InnerText;
int downNodeInt = Int32.Parse(downNodeValue);
downNodeInt = downNodeInt + 1;
var downNodeString = downNodeInt.ToString();
downNode.InnerText = downNodeString;
Func<string, int> ParseIntOrDefault = (string input) =>
{
int output;
int.TryParse(input, out output);
return output;
};
var result = doc.SelectNodes("MplAndSiImages/MplImages/*")
.Cast<XmlNode>()
.OrderBy(element => element.SelectSingleNode("pos").InnerText)
.ToList();
doc.Save(url);
return RedirectToAction("UploadAnImage", new { id = id });
}
I have seen this and tried it but is there any way of doing this with xmldocument:
XElement root = XElement.Load(xmlfile);
var orderedtabs = root.Elements("Tab")
.OrderBy(xtab => (int)xtab.Element("Order"))
.ToArray();
root.RemoveAll();
foreach(XElement tab in orderedtabs)
root.Add(tab);
root.Save(xmlfile);
I am ordering the images to display on a web page.
and when the move up button is pressed the image will be moved up in the list and swap places with the image above it.
Using linq to xml you can:
var result = XDocument.Load("data.xml")
.Descendants("ImageInfo")
.OrderBy(element => element.Element("pos")?.Value)
.ToList();
And in order to order it by the int value of it you can:
Func<string,int> ParseIntOrDefault = (string input) =>
{
int output;
int.TryParse(input, out output);
return output;
};
var result = XDocument.Load("data.xml")
.Descendants("ImageInfo")
.OrderBy(element => ParseIntOrDefault(element.Element("pos")?.Value))
.ToList();
Using XmlDocument to read the xml you can:
var doc = new XmlDocument();
doc.Load("data.xml");
var result = doc.SelectNodes("MplAndSiImages/MplImages/*")
.Cast<XmlNode>()
.OrderBy(element => element.SelectSingleNode("pos").InnerText)
.ToList();
Here too you can use the ParseIntOrDefault from above

XmlException unhandled

I want to load an XML file that I make by getting data from my database.
However, if I want to read that data, it says there"s an error on line 1.
Line 1 is strange indeed, because I never asked for "ArrayOfBand". But even when it's there I get all my Bands when i put a break point. It just crashes at the last step. Error HRESULT: 0xC00CE556
XAML on localhost
<ArrayOfBand xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/WindowsStoreApp.Models">
<Band>
<Description>Noorse DJ</Description>
<Facebook>Avicii</Facebook>
<ID>156</ID>
<Name>Avicii</Name>
<Picture>..\Images\Avicii.jpg</Picture>
<Twitter>#Avicii</Twitter>
</Band>
<Band>
<Description>Heavy Metal</Description>
<Facebook>A7X</Facebook>
<ID>157</ID>
<Name>Avenged Sevenfold</Name>
<Picture>..\Images\A7X.jpg</Picture>
<Twitter>#A7X</Twitter>
</Band>
</ArrayOfBand>
C# xml reader
string m_strFilePath = "http://localhost:17281/api/Band";
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load(m_strFilePath); //Load NOT LoadXml
XmlNodeList elemList = myXmlDocument.GetElementsByTagName("Band");
for (int i = 0; i < elemList.Count; i++)
{
XAML station = new XAML() {
ID = elemList[i].Attributes["ID"].InnerText,
Name = elemList[i].Attributes["Name"].InnerText
};
list.Add(station);
}
return list;
}
c# for creating the xml file
you can see I'm not asking for an "ArrayOfBand". If i take the file and remove "ArrayOfBand" it works perfectly. Anyone has an idea why it's there?
public static List GetBands()
{
List list = new List();
DbDataReader reader = Database.GetData("SELECT * FROM Band");
while (reader.Read())
{
Band b = new Band();
b.ID = reader["ID"].ToString();
b.Name = reader["Name"].ToString();
b.Picture = reader["Picture"].ToString();
b.Description = reader["Description"].ToString();
b.Twitter = reader["Twitter"].ToString();
b.Facebook = reader["Facebook"].ToString();
list.Add(b);
}
return list;
}
Your xml is badly formed. You need to have a closing </ArrayOfBand> at the end.

How to get the unescaped length of XElement inner text?

I try to parse the following Java resources file - which is an XML.
I am parsing using C# and XDocument tools, so not a Java question here.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="problem"> test </string>
<string name="no_problem"> test </string>
</resources>
The problem is that XDocument.Load(string path) method load this as an XDocument with 2 identical XElements.
I load the file.
string filePath = #"c:\res.xml"; // whatever
var xDocument = XDocument.Load(filePath);
When I parse the XDocument object, here is the problem.
foreach (var node in xDocument.Root.Nodes())
{
if (node.NodeType == XmlNodeType.Element)
{
var xElement = node as XElement;
if (xElement != null) // just to be sure
{
var elementText = xElement.Value;
Console.WriteLine("Text = '{0}', Length = {1}",
elementText, elementText.Length);
}
}
}
This produces the following 2 lines :
"Text = ' test ', Length = 6"
"Text = ' test ', Length = 6"
I want to get the following 2 lines :
"Text = ' test ', Length = 6"
"Text = ' test ', Length = 16"
Document encoding is UTF8, if this is relevant somehow.
string filePath = #"c:\res.xml"; // whatever
var xDocument = XDocument.Load(filePath);
String one = (xDocument.Root.Nodes().ElementAt(0) as XElement).Value;//< test >
String two = (xDocument.Root.Nodes().ElementAt(1) as XElement).Value;//< test >
Console.WriteLine(one == two); //false
Console.WriteLine(String.Format("{0} {1}", (int)one[0], (int)two[0]));//160 32
You have two different strings, and   is there, but in unicode format.
One possible way to get things back is manually replace non-breaking space to " "
String result = one.Replace(((char) 160).ToString(), " ");
Thanks to Dmitry, following his suggestion, I have made a function to make stuff work for a list of unicode codes.
private static readonly List<int> UnicodeCharCodesReplace =
new List<int>() { 160 }; // put integers here
public static string UnicodeUnescape(this string input)
{
var chars = input.ToCharArray();
var sb = new StringBuilder();
foreach (var c in chars)
{
if (UnicodeCharCodesReplace.Contains(c))
{
// Append &#code; instead of character
sb.Append("&#");
sb.Append(((int) c).ToString());
sb.Append(";");
}
else
{
// Append character itself
sb.Append(c);
}
}
return sb.ToString();
}

How can I get all text nodes from XML file

I want to get all text nodes from an XML file.
How can I do this?
Example Input:
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>
Expected Output:
hi this is A
The only solution (so far) to enumerate all text nodes in any xml, regardless of its structure:
string input = #"
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>";
foreach (XText text in (IEnumerable)XDocument.Parse(input).XPathEvaluate("//*/text()"))
{
Console.WriteLine(text.Value);
}
EDIT: if you want to load xml from file then use XDocument.Load instead.
This code will print the inner text of all xml nodes which doesnt have a child:
static void Main(string[] args)
{
XmlDocument x = new XmlDocument();
x.Load("exp.xml");
PrintNode(x.DocumentElement);
}
private static void PrintNode(XmlNode x)
{
if (!x.HasChildNodes)
Console.Write(string.Format("{0} ", x.InnerText));
for (int i = 0; i < x.ChildNodes.Count; i++)
{
PrintNode(x.ChildNodes[i]);
}
}
On your example XML it will result in the output you want :)
You can try this:
string input = #"
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>";
XDocument doc = XDocument.Parse(input);
//You can also load data from file by passing file path to Load method
//XDocument doc = XDocument.Load("Data.xml");
foreach(var slide in doc.Root.Elements("slide"))
{
var words = slide.Elements().Select(el => el.Value);
string s = String.Join(" ", words.ToArray());
}
This will work
static void Main(string[] args)
{
XDocument xmlSkuDescDoc = XDocument.Parse
(#"<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root> "
);
var result = (from data in xmlSkuDescDoc.Descendants("slide")
select data).Elements().Select(i => i.Value).Aggregate((a, b) => a + " " + b);
Console.ReadKey();
}
N.B.~ use XDocument.Load(filename) if loading from file
e.g.
string fileName = #"D:\MyXml.xml";
XDocument xmlSkuDescDoc = XDocument.Load(filename);
.... and the rest follows as shown above
It can be done using XDocument class (LINQ to XML). Assuming that you have exactly one slide element:
Using plain XDocument navigation:
var doc = XDocument.Load("file path here");
if (doc.Root == null)
throw new ArgumentException(); // No root node!
var slideElement = doc.Root.Element("slide");
if (slideElement == null)
throw new ArgumentException(); // No slide node!
var values = string.Join(" ", slideElement.Elements().Select(element => element.Value));
Using XPath node selection:
var doc = XDocument.Load("file path here");
var slideElements = doc.XPathSelectElements("root/slide/*");
var values = string.Join(" ", slideElements.Select(element => element.Value));

Categories

Resources