How to edit single line XML element with multiple values in c#? - c#

I am editing an existing XML file. I cannot edit an element (the element “range”) that is a multiple value element (a list or an array?), as shown in the XML code below.
<objects>
<PinJoint name="revolute">
<socket_parent_frame>torso_offset</socket_parent_frame>
<socket_child_frame>base_offset</socket_child_frame>
<coordinates>
<Coordinate name="revolute_angle">
<default_value>0</default_value>
<default_speed_value>0</default_speed_value>
<range>-1.5700000000000001 1.5700000000000001</range>
<clamped>true</clamped>
<locked>true</locked>
</Coordinate>
</coordinates>
I want to rewrite the values of the element “range”. In this case, these are two numeric values (doubles) separated by spaces.
I am trying to do this with the following c# code
XDocument xdoc = XDocument.Load(#"G:/My Drive/File.xml");
double r1 = new double[,] { {0.1745, 1.3963 } };
var pinjoints = xdoc.Root.Descendants("objects").Elements("PinJoint").Descendants("coordinates").Elements("Coordinate").FirstOrDefault(x => x.Attribute("name").Value == "revolute_angle");
pinjoints.SetElementValue("range", r1);
but the “range” element is rewritten as follow:
<range>System.Double[,]</range>
Can you please help me to edit the element “range” by rewriting one or all its numeric values?
Best regards
Andrés

You are passing array(r1) to the XML element as a value. XML elements accept string.
You can replace your code with the following code & it should work.
XDocument xdoc = XDocument.Load(#"G:/My Drive/File.xml");
double[] r1 = new double[] {0.1745, 1.3963 };
var str = string.Join(",",r1);
var pinjoints = xdoc.Root.Descendants("objects").Elements("PinJoint").Descendants("coordinates").Elements("Coordinate").FirstOrDefault(x => x.Attribute("name").Value == "revolute_angle");
pinjoints.SetElementValue("range", str);
Here, I have just used string.Join() method to produce comma separated string that can be easily passed to XML element.

Related

converting flat txt file to nested xml

I need to convert text file with some conversion columns-elements to an nested xml file -
for example
txt flat file - Name,Age,Street name,street number,city name
conversion table-
flat file - Name,Age,Street name,street number,city name
conversion table -
Name-FullName
Age-Age
Street Name-AddressDetail-StreetName
Street Number-AddressDetail-StreetNumber
City Name-AddressDetail-CityName
xml file
<?xml version="1.0" encoding="UTF-8"?>
<Envelop>
<FullName>Steve Mate</FullName>
<Age>22</Age>
<AddressDetail>
<StreetName>Rockford</StreetName>
<StreetNumber>111</StreetNumber>
<CityName>Alimena</CityName>
</AddressDetail>
</Envelop>
What is the best way to implement it?
Can it be used with MVC?
Using XElement?
The following code should work for you
var lines = text.Split(new[] {"\r", "\n", "\r\n"}, 0);
var xDoc = new XDocument(new XElement("Envelop"));
foreach (var line in lines)
{
var values = line.Split('-');
var parentNode = xDoc.Root;
foreach (var value in values.Reverse().Skip(1))
{
var name = value.Replace(" ", "");
var node = parentNode.Element(name);
if (node == null)
{
node = new XElement(name);
parentNode.Add(node);
}
parentNode = node;
}
parentNode.Value = values.Last();
}
Split the text based on newlines.
For each line, split it based on -
Take the root the starting node
For each value in the split line, skipping the first item...
Remove spaces (you can't have spaces in a node name).
Get the child node with that name
If it doesn't exist, create it.
Set the current parent as this node.
Finally set the value of this node to the last item in the split values
dotnetfiddle
Output:
<Envelop>
<FullName>FullName</FullName>
<Age>Age</Age>
<AddressDetail>
<StreetName>StreetName</StreetName>
<StreetNumber>StreetNumber</StreetNumber>
<CityName>CityName</CityName>
</AddressDetail>
</Envelop>
I've done similar a number of times.
There is no special trick to this. You will need to parse the input file to get the elements you need, and then you'll need to create an XML file with the data.
I don't know of any existing way to convert your particular text file format.

How do I retrieve an XDocument's Element Value in XML escaped format?

I am building an XDocument and I have unit tests to test the output. One of the things I want to test for is that invalid strings are being formatted for XML properly. I have discovered that calling .ToString() on the XDoc itself properly formats the invalid strings for XML. However, in my testing I am retrieving specific Elements or Attributes off of the XDoc and testing the values. This does not format the values for XML. How do I go about getting these values in their escaped format?
Answer: (thx Ed Plunkett)
myXDoc.Descendants("element2").First().FirstNode.ToString();
// result "Pork&Beans"
Sample:
var xml =
"<element1>" +
"<element2>Pork&Beans</element2>" +
"</element1>";
var myXDoc = XDocument.Load(xml);
var xDocString = myXDoc.ToString();
// result is formatted - <element1> <element2>Pork&Beans</element2> </element1>
var element2Value = myXDoc.Decendents("element2").First().Value;
// result is unformatted - Pork&Beans
Got it: Text elements in XML are nodes too.
var el2XML = myXDoc.Descendants("element2").First();
var porkAndAmpSemicolonBeans = el2XML.FirstNode.ToString();
You'll want to also check el2XML.Nodes.Count to make sure there's exactly one child in there.
System.Xml.XmlDocument is another option, because XmlNode has an InnerXml property that'll give you what you want:
var morePorkAndBeans = doc.SelectSingleNode("//element2").InnerXml;

Query Collection of all XML Elements

I'm looking to parse an XML file, and have the ability to search any element.
My XML code looks rather nontraditional (out of my control):
<DiagReport>
<LicensingData>
<ToolVersion>6.3.9431.0</ToolVersion>
<LicensingStatus>SL_LICENSING</LicensingStatus>
</LicensingData>
<Health>
<Result>PASS</Result>
<TamperedItems></TamperedItems>
</Health>
<Genuine>
<ServerProps>GenuineId</ServerProps>
</Genuine>
</DiagReport>
I'd like to load each singular element into a collection, i.e. one collection including ToolVersion, Result, etc. From there, I'd like to iterate through each element/name pair, and depending upon the element, do something different:
if (element.Equals(Result))
//do something with "PASS"
Is this possible to do with LINQ?
You can use LINQ to XML to iterate through all second level elements:
var xdoc = XDocument.Load(#"C:\test.xml");
foreach (var element in xdoc.Element("DiagReport").Elements().Elements())
{
if (element.Name == "Result")
{
string value = element.Value;
}
}
You can use Linq to Xml to query your Xml document, you can search Elements, Attributes and grab what you need.
More information can be found here: Basic Queries (LINQ to XML)
And you can creat simple querys like below.
XElement root = XElement.Parse(File.ReadAllText("C:\\Test.xml"));
var test = new
{
ToolVersion = root.Descendants("ToolVersion").FirstOrDefault().Value,
Result = root.Descendants("Result").FirstOrDefault().Value
};

Trying to read xml file with LINQ

I am trying to get the variable whitch is an integer, but it gives me a string.
XDocument xmlDoc = XDocument.Load(path);
var test = xmlDoc.Descendants("Variables").Elements("nom").Select(e => (int)e);
Console.WriteLine(test);
here is my xml file
<?xml version="1.0" encoding="utf-8"?><Variables><Site>Chand</Site><nom>12</nom></Variables>
The expression you entered is of type IEnumerable<int> and not a single int. Try appending .First() to get the first (and in this case only) element of the enumerable.
var test = xmlDoc.Descendants("Variables").Elements("nom").Select(e => (int)e).First();

C# - Linq to XML - Exclude elements from query

I have this XML file:
<MyXml>
<MandatoryElement1>value</MandatoryElement1>
<MandatoryElement2>value</MandatoryElement2>
<MandatoryElement3>value</MandatoryElement3>
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
<MyXml>
All 3 elements that are called 'MandatoryElementX' will always appear in the file. The elements called 'CustomElementX' are unknown. These can be added or removed freely by a user and have any name.
What I need is to fetch all the elements that are not MandatoryElements. So for the file above I would want this result:
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
I don't know what the names of the custom elements may be, only the names of the 3 MandatoryElements, so the query needs to somehow exclude these 3.
Edit:
Even though this was answered, I want to clarify the question. Here is an actual file:
<Partner>
<!--Mandatory elements-->
<Name>ALU FAT</Name>
<InterfaceName>Account Lookup</InterfaceName>
<RequestFolder>C:\Documents and Settings\user1\Desktop\Requests\ALURequests</RequestFolder>
<ResponseFolder>C:\Documents and Settings\user1\Desktop\Responses</ResponseFolder>
<ArchiveMessages>Yes</ArchiveMessages>
<ArchiveFolder>C:\Documents and Settings\user1\Desktop\Archive</ArchiveFolder>
<Priority>1</Priority>
<!--Custom elements - these can be anything-->
<Currency>EUR</Currency>
<AccountingSystem>HHGKOL</AccountingSystem>
</Partner>
The result here would be:
<Currency>EUR</Currency>
<AccountingSystem>HHGKOL</AccountingSystem>
You can define a list of mandatory names and use LINQ to XML to filter:
var mandatoryElements = new List<string>() {
"MandatoryElement1",
"MandatoryElement2",
"MandatoryElement3"
};
var result = xDoc.Root.Descendants()
.Where(x => !mandatoryElements.Contains(x.Name.LocalName));
Do you have created this xml or do you get it by another person/application?
If it's yours I would advise you not to number it. You can do something like
<MyXml>
<MandatoryElement id="1">value<\MandatoryElement>
<MandatoryElement id="2">value<\MandatoryElement>
<MandatoryElement id="3">value<\MandatoryElement>
<CustomElement id="1">value<\CustomElement>
<CustomElement id="2">value<\CustomElement>
<MyXml>
In the LINQ-Statement you don't need the List then.
Your question shows improperly formatted XML but I am assuming that is a typo and the real Xml can be loaded into the XDocument class.
Try this...
string xml = #"<MyXml>
<MandatoryElement1>value</MandatoryElement1>
<MandatoryElement2>value</MandatoryElement2>
<MandatoryElement3>value</MandatoryElement3>
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
</MyXml> ";
System.Xml.Linq.XDocument xDoc = XDocument.Parse(xml);
var result = xDoc.Root.Descendants()
.Where(x => !x.Name.LocalName.StartsWith("MandatoryElement"));
lets say TestXMLFile.xml will contain your xml,
XElement doc2 = XElement.Load(Server.MapPath("TestXMLFile.xml"));
List<XElement> _list = doc2.Elements().ToList();
List<XElement> _list2 = new List<XElement>();
foreach (XElement x in _list)
{
if (!x.Name.LocalName.StartsWith("Mandatory"))
{
_list2.Add(x);
}
}
foreach (XElement y in _list2)
{
_list.Remove(y);
}

Categories