0

I want to change the value of an existing attribute's value using C#.

I can't seem to find the answer to this on the Googles, probably because I don't know the terminology well enough to ask the question intelligently.

I can find:

  • lots of ways to write a new xml doc, with new elements\attributes
  • ways to read the value of an existing element's attribute

But I can't find a way to drill down to an already existing element's attribute and change the value of that attribute.

To provide context, let's say that this is the xml file called "stuff.xml" located at C:\stuff.xml:

<?xml version="1.0" encoding="utf-8"

<configuration>
    <add key="apple" 
         value="red"/>
    <add key="school_bus" 
         value="yellow"/>
    <add key="grass" 
         value="orange"/>
    <system.Net>
          <binding>
                <endpoint address="https://1111.11.11.11:7276/Service"
                          binding="basicHttpBinding"/>
                 <endpoint address="http://localhost/Service"
                           binding="advancedHttpBinding"/>
           </binding>
</configuration>

What I'd like to do -- without using LINQ -- is to change the color value for grass to "green" and change the address for the first endpoint to https://222.22.22.22:7276/Service.

(I'm not married to not using LINQ, just, as a non-LINQ user I find it to be unreadable.)

I'm sure there's a way to do this! (And it's probably easy to find -- I just can't find it.)

I imagine that the answer will use the XmlWriter object, it's just that I don't know how to drill down to a sub-element and then use the XmlWriter object.


@maccettura: your suspicious mind is correct... sort of. It is a config file, but it's not the app.config file. And it has to change. Um... serialize. OK. I've sort of looked at that, but I always thought that to serialize was to basically read the values of the entire file into an object, then you could do with it what you will... I will look into that. Thank you.

Bob
  • 369
  • 1
  • 4
  • 24
  • Can't you just deserialize, change the value then serialize again? Also, the XML you provided looks suspiciously like a web.config/app.config. You should not be changing these values via code, they should be read-only. – maccettura Jan 23 '18 at 18:28
  • 3
    `as a non-LINQ user` you should become a LINQ user, then use LINQ – Jonesopolis Jan 23 '18 at 18:31
  • @maccettura: see edit for response. AT Jonesopolis: I'd rather join Jonestown then use LINQ. Actually, I do need to learn LINQ. I just don't have the time to do that right this very second, what with those damned deadlines and whatnot. – Bob Jan 23 '18 at 18:36
  • You should clarify what you mean by "not use LINQ." I have found that when many people say that it's specifically the long method chains and/or the "from/where" query syntax they want to avoid, but LINQ also technically includes stuff like XDocument, which is the simplest way to achieve most XML manipulation in C#. I'm also not sure if your goal is to specifically avoid deserializing (reading the XML into memory in object form), or how general you want to be (you could just do a string replacement). – nlawalker Jan 23 '18 at 18:44
  • OK. Everyone has convinced me. I'll learn Linq. Geez... – Bob Apr 04 '18 at 15:23

3 Answers3

3

You should use LINQ to XML, because it's almost absurdly easy:

var xml = XDocument.Parse(@"C:\stuff.xml");

xml.XPathSelectElement("configuration/add[@key='grass']")
  ?.SetAttributeValue("value", "green")

xml.XPathSelectElement("configuration/system.Net/binding/endpoint[@address='https://1111.11.11.11:7276/Service']")
  ?.SetAttributeValue("address", "https://222.22.22.22:7276/Service")

Or, if you don't like the XPath syntax:

xml.Root
   .Elements("add")
   .Where(o => (string)o.Attribute("key") == "grass")
   .FirstOrDefault()
  ?.SetAttributeValue("color", "green");

xml.Root
   .Element("system.Net")
  ?.Element("binding")
  ?.Elements("endpoint")
   .FirstOrDefault(o => (string)o.Attribute("address") == "https://1111.11.11.11:7276/Service")
  ?.SetAttributeValue("address", "https://222.22.22.22:7276/Service")

Either way, saving the file is easy:

xml.Save(@"C:\stuff.xml")
Mike Strobel
  • 25,075
  • 57
  • 69
1

Check out the response to this question, look for the answer that uses XmlDocument since you don't want to use LINQ. How to change XML Attribute

Yves Rochon
  • 1,492
  • 16
  • 28
0

You can serialize, read, and deserialize your xml file into an object in your code.

        YourObjectClass yourObjectName = new YourObjectClass();

        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(YourObjectClass));

            using (TextReader reader = new StreamReader(locationString))
            {
               yourObjectName = (YourObjectClass)serializer.Deserialize(reader);
            }
        }
        catch (Exception ex)
        {
            //do whatever you need to with caught exceptions here.
        }

And your class will look something like this:

[Serializable]
public class YourObjectClass
{
    public string StringValue1 { get; set; }

    public string StringValue2{ get; set; }

    [XmlElement("YourOtherObjectClass")]
    public List<YourOtherObjectClass> OtherObjectClassList = new List<YourOtherObjectClass>();
}

[Serializable]
public class YourOtherObjectClass
{
    public string StringValue1 { get; set; }
}

You will need:

using System.Xml.Serialization;

This is literally the simplest way to bring xml into code to work with. You can probably do fewer lines if you really try, but this is short and clean. You can then manipulate any of those values in your code to suit your need before using them.

As stated in the comment, if you are reading a config you probably shouldn't edit it in code and then save it. But if you have some logic that needs to use different values in different situations, then deserialize your xml to an object and then manipulate it. That's what objects are for.

user7396598
  • 1,269
  • 9
  • 6