1

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"));
user2939293
  • 793
  • 5
  • 16
  • 41

3 Answers3

3

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.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • +1 Concatenating the ID into an XPath somewhat defeats the purpose of using Linq to XML, so I think this is the preferable approach if you're using Linq to XML in the first place. – JLRishe Oct 31 '13 at 10:55
1

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";
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • This approach would carry the risk of an injection vulnerability, if `myVariable` contained user input. A way to migrate that while keeping XPath as a selection method is shown [here](http://stackoverflow.com/a/19513802/18771). – Tomalak Oct 31 '13 at 07:30
  • Putting the ID in an `XName` _would_ prevent XPath injection, but for all the wrong reasons, and it would prevent using IDs that could be entirely valid. Try using the ID `1234`. You'll encounter an exception when trying to assign the value to `myVariable`. – JLRishe Oct 31 '13 at 08:50
0

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

Herm
  • 2,956
  • 19
  • 32
  • Thank you! I tried both [@id = '" + myVariable + "'] and [@id = '{0}']/firstname", myVariable)); and they both worked! Charlotte – user2939293 Oct 31 '13 at 07:44