I want to find out if some string has a match in an XML file.
for example:
string test="New York, USA";
in an XML file formated this way:
<?xml version="1.0"?>
<line>
<word>New</word>
<word>York,</word>
<word>USA</word>
</line>
so that every word may or may not be in a different element
What is the most easiest way to do this?
I was thinking about matching each word separately while saving the partial results but it seems to me like there have to be easier way.
If you want to compare word by word you can compare this using two string lists.
using below you can get xml to List
List<string> list = doc.Root.Descendants("line").Descendants()
.Select(element => element.Value)
.ToList();
Then take your comparison string to list
string words = "New York, USA";
List<string> result = words.Split(' ').ToList();
Compare both lists using Intersect(). refer this
var matcheditems = list.Intersect(result);
Hope this will help you.
Related
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.
--edit
I will worry about memory stream later, how do I combined the strings first and print the output?
--edit
string1 xml
<study-groups>
<study-group>
<name></name>
<uuid></uuid>
<href></href>
</study-group>
</study-groups>
xml string2
<studies>
<study>
<name>someValue</name>
<uuid>someValue</uuid>
<href>someValue</href>
<parent-uuid>someValue</parent-uuid>
<created-at>2015-08-12T17:51:03Z</created-at>
<updated-at>2016-06-18T05:53:01Z</updated-at>
</study>
<study>
<name></name>
<uuid></uuid>
<href></href>
<parent-uuid></parent-uuid>
<created-at>2015-08-12T17:51:03Z</created-at>
<updated-at>2016-06-18T05:53:01Z</updated-at>
</study>
</studies>
I am looping through API HTTP requests and saving the output xml to a string and to a memory stream.
the first foreach loop produces a single xml file.
in my second for each loop, it returns multiple files.
I want to join string1 and string2 to create string 3 without duplicates and pass string 3 into the third 4 each loop.
var xml1 = XDocument.Parse(string1);
var xml2 = XDocument.Parse(string2);
//Combine and remove duplicates
var string3 = xml1.Descendants("study-groups")
.Union(xml2.Descendants("studies"));
Console.WriteLine("---------------------string 3---------------------------");
Console.WriteLine(string3.ToString());
Console.WriteLine("---------------------string 3---------------------------");
//Combine and keep duplicates
var combinedWithDups = xml1.Descendants("study-groups")
.Concat(xml2.Descendants("studies"));
foreach (var i in combinedUnique)
{
Console.WriteLine("---------------------combinednodups---------------------------");
Console.WriteLine("{0}", i);
Console.WriteLine("---------------------combinednodups---------------------------");
}
but my output keeps coming out as:
System.Linq.Enumerable+UnionIterator2`1[System.Xml.Linq.XElement]
If the problem is simply the output, it's because calling ToString() on an IEnumerable (like most types) will simply print the name of the type.
Instead you could do:
// Join each element in the IEnumerable with a line break
Console.WriteLine(string.Join(Environment.NewLine, string3));
This will produce the following with your example input:
<study-groups>
<study-group>
<name></name>
<uuid></uuid>
<href></href>
</study-group>
</study-groups>
<studies>
<study>
<name>someValue</name>
<uuid>someValue</uuid>
<href>someValue</href>
<parent-uuid>someValue</parent-uuid>
<created-at>2015-08-12T17:51:03Z</created-at>
<updated-at>2016-06-18T05:53:01Z</updated-at>
</study>
<study>
<name></name>
<uuid></uuid>
<href></href>
<parent-uuid></parent-uuid>
<created-at>2015-08-12T17:51:03Z</created-at>
<updated-at>2016-06-18T05:53:01Z</updated-at>
</study>
</studies>
However, if that's all you want, there's no need for using an XDocument. You can simply concatenate the two strings:
var string3 = string1 + Environment.NewLine + string2;
Console.WriteLine(string3);
I have a situation here, I have to write a simple WPF apps with a textbox and a button, textbox is for "en", "fr", "ru", etc...
I have a lot of files with huge number of data like this. Consider this is a file
<?xml version="1.0" encoding="UTF-8"?>
<params>
<btestsir xml:lang="fr" tId="HHXAF">Test Sirène :</btestsir>
<btestsir xml:lang="en" tId="HHXAF">Test Siren :</btestsir>
<btestsir xml:lang="pt" tId="HHXAF">Testar sirene:</btestsir>
<btestsir xml:lang="ru" tId="HHXAF">Тест сирены:</btestsir>
<btestbeep xml:lang="fr" tId="HHXA2">Test Bip :</btestbeep>
<btestbeep xml:lang="en" tId="HHXA2">Test Beep :</btestbeep>
<btestbeep xml:lang="pt" tId="HHXA2">Testar aviso sonoro:</btestbeep>
<btestbeep xml:lang="ru" tId="HHXA2">Тест гудка:</btestbeep>
</params>
Now if I select "en" through my application, and click on the button then only two strings whose xml:lang="en" values match will be copied to an excel sheet. and would display something like this.
For English language
For Russian language
I have tried this
StreamReader reader = new StreamReader(strFilepath);
string line;
while(null != (line = reader.ReadLine()))
{
string[] s1 = line.Split('>');
string[] s2 = s1[1].Split('<');
if(s1[0].Contains("xml:lang="))
{
}
}
Logic behind this is simple first I want to split every line using ">"
So s1[0] will have <btestsir xml:lang="fr" transId="HHXAF"
s1[1] will have Test Sirène :</btestsir>
But here the problem I am facing is how to fetch the "key" for a specific language xml:lang= and put that key-value pair to excel sheet, As I have shown in the picture. Fetching the "value" is easy s2[0] will have the value.
But this two key-value pair should be match and then put into the excel sheet, then it will again continue for the next line.
Edit: One point here the key value pair should be put into different excel-sheet for different language files. excel-sheet.en.xlsx will contain all "en", excel-sheet.fr.xlsx will contain all "fr", etc
As I said I have huge files and it should work seamlessly without manual intervention.
Can you help me please!
Thanks
I would use xpath selectors and not try string manipulation of an xml file. So you could do something like declare a nodelist variable and populate it ie:
using System.xml;
...
XmlNodeList childNodes;
childNodes = xml.SelectNodes("ParentNodeofbtestsirNode/btestsirnode[#lang='en']);
...
and go on from there doing your manipulations against each XmlNode such as
foreach(XmlNode xnd in childNodes)
{
'...
}
Something like this should do it:
XmlDocument doc = new XmlDocument();
doc.Load("sample.xml");
var root = doc.DocumentElement;
var elements = root.XPathSelectElements("//[#xml:lang='en']");
foreach (var child in elements)
{
//child.Name >> will give you btestsir
//child.Value >> will give you Test Siren :
}
And to create/manage spreadsheets use EPPlus see sample here
I have an xml string and have different records within and i want to extract the id within each record. Here is a sample of the xml:
<UploadsInformation >
<Record>
<TaskGUID>48A583CA-A532-419A-9CDB-292764CEC541</TaskGUID>
</Record>
<Record>
<TaskGUID>ED6BA682-2BB2-4ADF-8355-9C605E16E088</TaskGUID>
</Record>
<Record>
<TaskGUID>D20D7042-FC5B-4CF7-9496-D2D9DB68CF52</TaskGUID>
</Record>
<Record>
<TaskGUID>F5DB10C5-D517-4CDA-8AAA-4E3F50B5FF3C</TaskGUID>
</Record>
</UploadsInformation>
This is what i have as a string to extract the information that i need but not sure if it correct or not because when i debug the string seems to be the xml file and not just the specified guid.
string data = new XDocument(new XElement("Record",
uploads.Select(guid => new XElement("TaskGUID", guid.ToString()))))
.ToString();
uploads is: List<Guid?> uploads
If I understand your question correctly, you want to extract the Guids from the source XML, which you indicate is a string.
You can create an XDocument from a string with the following command:
XDocument doc = XDocument.Parse(xmlString);
XNamespace ns = "http://schemas.acatar.com/2013/03/Malt.Models";
List<string> uploads = doc.Descendants(ns + "TaskGUID")
.Select(x => x.Value).ToList();
string uploadString = String.Join(",", uploads);
I used XNamespace because there is a namespace (two, actually) defined in the XML, and unless you prefix the correct one to the element name you won't get any results.
You might be able to combine the last two steps into one line, but I'm not 100% sure.
The above code was tested with your example, and produces the following value for uploadString:
48A583CA-A532-419A-9CDB-292764CEC541,ED6BA682-2BB2-4ADF-8355-9C605E16E088,D20D7042-FC5B-4CF7-9496-D2D9DB68CF52,F5DB10C5-D517-4CDA-8AAA-4E3F50B5FF3C
However, if you're going to loop through the result and pass each one in singularly to a stored procedure, I'd skip the String.Join and just loop through the List:
foreach (string id in uploads)
{
// Do your stored procedure call for each Guid.
}
Added in Response to Comment
In the situation in your comment, if you have a List that you want to get the values for, you'd do essentially the same, but you'll need to check for nulls and (probably) convert the Guid to a string before passing it into the stored proc:
foreach (Guid? g in uploads)
{
if (g != null)
{
string newGuid = g.ToString();
// do your data access stuff here
}
}
You can't use local names of elements, because you have namespace declared. So, you should use namespace to provide names:
XNamespace ns = "http://schemas.acatar.com/2013/03/Malt.Models";
var guids = from r in xdoc.Root.Elements(ns + "Record")
select Guid.Parse((string)r.Element(ns + "TaskGUID"));
Or query your xml without specifying names of elements:
var guids = xdoc.Root.Elements()
.Select(r => Guid.Parse((string)r.Elements().Single()));
I think this is either what you are after or perhaps might shed some light on the direction to go:
string xml = ""; // XML data here
XDocument doc = XDocument.Parse(xml);
List<Guid> guids = doc.Descendants("TaskGUID")
.Select(g => new Guid(g.Value))
.ToList();
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);
}