I'm using XPathSelectElement to store data into an XML file. How can I in the code snippet below use a global variable name instead of id name 'City1'?
I want the code to be:
string myVariable = "City1"
XElement fname= country.XPathSelectElement("country/city/major[#id = myVariable]/firstname");
Thank you for your help
This is my XML:
<country>
<city>
<cityname>City1</cityname>
<citynr>111</citynr>
<person>
<name>Person1</name>
<name>Person2</name>
<name>Person3</name>
<name>Person4</name>
</person>
<major id=City1>
<firstname>Major1firstname</firstname>
<lastname>Major1lastname</lastname>
</major>
</city>
<city>
<cityname>City2</cityname>
<citynr>222</citynr>
<person>
<name>Person5</name>
<name>Person6</name>
<name>Person7</name>
<name>Person8</name>
</person>
<major id=City2>
<firstname>Major2firstname</firstname>
<lastname>Major2firstname</lastname>
</major>
</city>
</country>
Here is my code:
XDocument country= XDocument.Load(Server.MapPath("myXML.xml"));
XElement fname= country.XPathSelectElement("country/city/major[#id = 'City1']/firstname");
XElement lname= country.XPathSelectElement("country/city/major[#id = 'City1']/lastname");
fname.Value = firstname.Text;
lname.Value = lastname.Text;
country.Save(Server.MapPath("myXML.xml"));
I'd just use the selection methods within LINQ to XML instead:
XElement fname = country.Element("country")
.Elements("city")
.Elements("major")
.Where(x => (string) x.Attribute("id") == myVariable)
.Elements("firstname")
.FirstOrDefault();
(By using FirstOrDefault, the result will be null if no such element is found.)
You may use:
var fname = country
.XPathSelectElement(
"//country/city/major[#id = '" + myVariable + "']/firstname");
or
var fname = country
.XPathSelectElement(
String.Format("//country/city/major[#id = '{0}']/firstname", myVariable));
I believe that one way through which you might mitigate the XPath injection that #Tomalak mentions in the comment below is to use the XName type instead of string (exception handling left out of scope intently):
XName myVariable = "City1";
you are either looking for string.Format or the StringBuilder class.
fname= country.XPathSelectElement(string.Format("country/city/major[#id = '{0}']/firstname",myVariable));
references:
http://msdn.microsoft.com/de-de/library/fht0f5be(v=vs.85).aspx
http://msdn.microsoft.com/de-de/library/2839d5h5(v=vs.90).aspx
Related
I have this XML:
<?xml version="1.0" encoding="UTF-8"?>
<TXLife xmlns="http://ACORD.org/Standards/Life/2" Version="2.22.00">
<TXLifeRequest>
<OLifE Version="2.22.0">
<Party id="BEB7-BDDC43FE3F01_10004">
<PartyTypeCode tc="1">PT_PERSON</PartyTypeCode>
<FullName>Gump,Forrest</FullName>
<ResidenceState tc="58">USA_WI</ResidenceState>
<Person id="D7329BB530E8_10304">
<FirstName>Forrest</FirstName>
<LastName>Gump</LastName>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
I want Replace the FirstName value to No Name.
This is related to Data Masking.
I'm trying to access the node with the given code below, but it is not working.
var testXML = XDocument.Load("C:\\DataMask\\P0500015703691806181259345440127.xml");
var nodePTCode = testXML.Descendants("Party").FirstOrDefault(cd => cd.Element("PartyTypeCode").Value == "PT_PERSON");
The namespace has to be included when addressing the elements.
Also for an XDocument you have to start from its Root property.
XDocument xdoc = XDocument.Load("C:\\DataMask\\P0500015703691806181259345440127.xml");
XNamespace ns = "http://ACORD.org/Standards/Life/2";
XElement firstName = xdoc.Root.Descendants(ns + "FirstName").FirstOrDefault();
if (firstName != null) { firstName.Value = "No Name"; }
The xml will have the update applied:
<TXLife xmlns="http://ACORD.org/Standards/Life/2" Version="2.22.00">
<TXLifeRequest>
<OLifE Version="2.22.0">
<Party id="BEB7-BDDC43FE3F01_10004">
<PartyTypeCode tc="1">PT_PERSON</PartyTypeCode>
<FullName>Gump,Forrest</FullName>
<ResidenceState tc="58">USA_WI</ResidenceState>
<Person id="D7329BB530E8_10304">
<FirstName>No Name</FirstName>
<LastName>Gump</LastName>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
Edit
If applicable, you'll also have to update the FullName xml element to reflect the change in FirstName.
XElement lastName = xdoc.Root.Descendants(ns + "LastName").FirstOrDefault();
XElement fullName = xdoc.Root.Descendants(ns + "FullName").FirstOrDefault();
fullName.Value = String.Format("{0},{1}", (String)lastName, (String)firstName);
I have the string which has the XML tag like
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<lab:lab xmlns:udf="http://ghjhjhj.com/ri/userdefined"
xmlns:ri="http://kjkj.com/ri"
xmlns:lab="http://iuiuu.com/ri/lab"
uri="https://hhjjhjhj.org/api/v2/labs/1">
<name>Administrative Lab</name>
<billing-address>
<street></street>
<city></city>
<state></state>
<country></country>
<postalCode></postalCode>
<institution></institution>
<department></department>
</billing-address>
<shipping-address>
<street></street>
<city></city>
<state></state>
<country></country>
<postalCode></postalCode>
<institution></institution>
<department></department>
</shipping-address>
<udf:field type="String" name="Account ID">adm</udf:field>
<website></website>
</lab:lab>"
In order to just extract the value adm i.e any value between the <udf> tag should I be using the XDocument or the XmlDocument.I understand I can use XDocument.Parse but this I am not sure how to give the tag name. I tried below
XDocument new_doc = XDocument.Parse(new_responseString);
var a = from udf in new_doc.Descendants("udf") select udf.Value;
But there can be additional udf fields in future so what will I be checking should be name="Account ID" and I am not sure how to do this
How can I retrieve this?
You can use Attribute method for retrieving attribute's value of XElement.
var udf = "http://ghjhjhj.com/ri/userdefined";
var new_doc = XDocument.Parse(new_responseString);
var fieldValues = doc.Descendants(udf + "field")
.Where(field => field.Attribute("name").Value.Equals("Account ID"))
.Select(field => field.Value);
foreach (var value in fieldValues)
{
Console.WriteLine(value);
}
If you need only one value then use FirstOrDefault method
var fieldValue =
doc.Descendants(udf + "field")
.FirstOrDefault(field => field.Attribute("name").Value.Equals("Account ID"))
.Value;
But be aware - this query will throw exception of there no elements with attribute name = "Account ID"
Probably this might do the trick for you
XNamespace laburi = "http://iuiuu.com/ri/lab";
XNamespace udfuri = "http://ghjhjhj.com/ri/userdefined";
XDocument xdoc = XDocument.Load("some.txt");
var a = xdoc.Elements(laburi + "lab").Elements(udfuri + "field").FirstOrDefault().Value;
**I have an XML like this-
<?xml version="1.0" encoding="UTF-8"?>
<Tool_Parent>
<tool name="ABCD" id="226">
<category>Centralized</category>
<extension_id>0</extension_id>
<uses_ids>16824943 16824944</uses_ids>
</tool>
<tool name="EFGH" id="228">
<category>Automated</category>
<extension_id>0</extension_id>
<uses_ids>92440 16824</uses_ids>
</tool>
</Tool_Parent>
Based on the id of tool i want to print the uses_ids value,i.e if i search for 228 i should get 92440 16824.
I had tried like-
var toolData = (from toolElement in doc.Descendants("tool")
select new Tool_poco
{
a_Name = tool.Attribute("name").Value,
a_Id = tool.Attribute("id").Value,
e_ExtensionId = tool.Element("extension_id").Value,
e_UsesIds =tool.Element("uses_parm_ids").Value
});
where Tool_poco is a poco class for tool node containing declaration for member variable.
Now I want to get information related to a particular tool id in toolData variable.How to do it?
Note: I have variable like-
searched_Tool_id = Tool_Id_txtBx.Text.ToString();
Please let me know a way through which i can modify my above query for toolData.**
You can modify your query as
Tool_poco toolData = (from el in xelement.Elements("Employee")
where (string)el.Attribute("id") == "226"
select new Tool_poco
{
a_Name = el.Attribute("name").Value,
a_Id = el.Attribute("id").Value,
e_ExtensionId = el.Element("Name").Value,
e_UsesIds = el.Element("uses_ids").Value
}).FirstOrDefault();
You could start by doing something like this once you have an XDocument object loaded and ready:
var xdoc = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""utf-8""?>
<Tool_Parent>
<tool name=""ABCD"" id=""226"">
<category>Centralized</category>
<extension_id>0</extension_id>
<uses_ids>16824943 16824944</uses_ids>
</tool>
<tool name=""EFGH"" id=""228"">
<category>Automated</category>
<extension_id>0</extension_id>
<uses_ids>92440 16824</uses_ids>
</tool>
</Tool_Parent>");
var root = xdoc.Root; // Got to have that root
if (root != null)
{
var id228query = (from toolElement in root.Elements("tool")
where toolElement.HasAttributes
where toolElement.Attribute("id").Value.Equals("228")
let xElement = toolElement.Element("uses_ids")
where xElement != null
select xElement.Value).FirstOrDefault();
Console.WriteLine(id228query);
Console.Read();
}
Output: 92440 16824
**Note: In reference to your example, one possible reason it was not working
for you could be that your xml references an element with name "uses_ids",
however, your query references an element with a similar, but not exact,
spelling with name "uses_parm_ids".**
I am trying to display some date from some XML I get from an external service. I am using XElement and I try to use LINQ select to get my data.
var xElem = XElement.Load(HttpUtility.UrlPathEncode(url));
var books = (from pubs in xElem.Elements("result")
select new
{
Id = (string)pubs.Element("data").Element("id"),
Title = (string)pubs.Element("data").Element("title"),
Year = (string)pubs.Element("data").Element("year"),
Resources = (string)pubs.Element("data")
.Element("resource")
.Element("url")
.ElementValueNull(),
Authors= pubs.Element("data").Elements("person")
}).ToList();
foreach (var book in books)
{
// Put the string together with string builder....
foreach (var person in book.Authors)
{
//Get the authors
}
}
And of course I have made the class for ElementValueNull.
//This method is to handle if element is missing
public static string ElementValueNull(this XElement element)
{
if (element != null)
return element.Value;
return "";
}
//This method is to handle if attribute is missing
public static string AttributeValueNull(this XElement element, string attributeName)
{
if (element == null)
return "";
else
{
XAttribute attr = element.Attribute(attributeName);
return attr == null ? "" : attr.Value;
}
}
The problem is that the resource tag with it's elements are not always present. And if it isn't there it will skip the whole record. Is there any easy way of making it so that it will just make the Resources have the empty string returned from my class but still add the record still using a LINQ select?
EDIT with XML example:
<?xml version="1.0" encoding="UTF-8"?>
<tester xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://tester.no/xmlSchema/xsd/tester.xsd">
<generert>2014-12-01</generert>
<result>
<data>
<id>297474</id>
<person>
<id>11690</id>
<surname>Medel-Svensson</surname>
<firstname>Ronnie</firstname>
</person>
<title>Title 1</title>
<year>2009</year>
</data>
</result>
<result>
<data>
<id>807059</id>
<person>
<id>11690</id>
<surname>Bronskimlet</surname>
<firstname>Hallstein</firstname>
</person>
<person>
<id>328009</id>
<surname>Kroksleiven</surname>
<firstname>Jostein</firstname>
</person>
<person>
<id>328010</id>
<surname>Gassolini</surname>
<firstname>Ruffino</firstname>
</person>
<person>
<id>327990</id>
<surname>von Schnellfahrer</surname>
<firstname>Heinrich</firstname>
</person>
<title>Title 2</title>
<year>2010</year>
<resource>
<type>
<code>TEXT</code>
</type>
<url>http://www.example.com/</url>
</resource>
</data>
</result>
<result>
<data>
<id>1164653</id>
<person>
<id>11690</id>
<surname>Bergsprekken</surname>
<firstname>Mysil</firstname>
</person>
<title>Title 3</title>
<year>2014</year>
<resource>
<type>
<code>FULLTEKST</code>
</type>
<url>http://www.example.com/</url>
</resource>
</data>
</result>
</tester>
A couple of things:
if you use Element(..), then the result could be null. This may cause null reference exceptions if elements are missing in your path. A more elegant way to handle this would be to use sequences and return an element if present using SingleOrDefault()
Both XElement and XAttribute have a bunch of explicit type conversion operators built in. This means you can cast to string and various other primitives. As string is a reference type, it would return null if the XObject was null. Value types such as int would throw an exception in this case, though int? would not.
With this in mind, something like this should solve your problem. Note as 'data' is common to all, you can put this in the initial selector:
from pubs in xElem.Elements("result").Elements("data")
select new
{
Id = (string)pubs.Element("id"),
Title = (string)pubs.Element("title"),
Year = (string)pubs.Element("year"),
Resources = (string)pubs.Elements("resource")
.Elements("url")
.SingleOrDefault(),
Authors= pubs.Elements("person")
}
I have a xml structure like this. Can anyone help with a simple linq function to read this xml structure.The itemEntry node repeats according to data. I tried to read the xml using the method below,but i am getting no records in the list. Is this method here correct way to get the details...
List<CX_ITEMLIST> sList =
(from e in XDocument.Load(param.FileName).Root.Elements("itemEntry")
select new CX_ITEMLIST
{
TITLE = (string)e.Element("title"),
YEAR = (string)e.Element("year"),
ITEMNAME = (string)e.Element("itemname"),
CATRYLIST =
(
from p in e.Elements("categorylist").Elements("categories")
select new CATLIST
{
IDTYPE = (string)p.Element("categoryid"),
IDNUMBER = (string)p.Element("categoryName")
}).ToList()
}).ToList();
<itemslist>
<itemInformation>
<itemdate>01/23/2014</itemdate>
<itemcount>57</itemcount>
</itemInformation>
<itemEntry>
<title>Title1</title>
<year>2013</title>
<itemname>testname</itemname>
<categorylist>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
</categorylist>
</itemEntry>
<itemEntry>
<title>Title1</title>
<year>2013</title>
<itemname>testname</itemname>
<categorylist>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
</categorylist>
</itemEntry>
</itemslist>
You should try with XDocument.
XDocument xdoc = XDocument.Load("file.xml");
The System.Xml.XLinq namespace contains some awesome objects to make this easy.
var xDoc = XDocument.Parse(xml); // load your xml string, or use XDocument.Load() to load an xml file
var itemEntries = xDoc
.Root // refers to itemEntries node
.Descendants("itemEntry"); // gets all itemEntry nodes in an IEnumerable object
This gets you an IEnumerable<XNode> of all the itemEntry nodes.
From there you can do what you need, save the values to a business object, etc.
The above method works properly, i found the issue, my xml tag was having namespace attribute. i tried to get the namespace and append it with Elements while reading
XNamespace ns = xDocument.Root.Attribute("xmlns").Value;
List<CX_ITEMLIST> sList =
(from e in XDocument.Load(param.FileName).Root.Elements(ns + "itemEntry")
select new CX_ITEMLIST
{
TITLE = (string)e.Element(ns + "title"),
YEAR = (string)e.Element(ns + "year"),
ITEMNAME = (string)e.Element(ns + "itemname"),
CATRYLIST =
(
from p in e.Elements(ns + "categorylist").Elements(ns + "categories")
select new CATLIST
{
IDTYPE = (string)p.Element(ns + "categoryid"),
IDNUMBER = (string)p.Element(ns + "categoryName")
}).ToList()
}).ToList();