How to add a namespace to specific attributes using linq?

We're creating JSON from XML using NewtonSoft's standard .NET functionality. We know that we need to use namespace to define values to be an array as @Json:Array="true" but we then run into some issues when trying to use the namespace when returning XML from SQL Server.

What we'd like to do is specify in SQL Server Array="true" and then post-process the XML to add the @Json namespace prefix.

Is there an XElement method (maybe using LINQ ?) that we can do this in one hit, i.e., add the JSON namespace prefix to all attributes called "Array" ? We'd prefer not to convert the XElement to a string and do a find / replace (which we've done to test it so far) or to have to tree-walk the elements as I can't imagine that would be very performant.

Jon Skeet
people
quotationmark

You have to do a tree-walk, I believe.

If you want to keep all the attributes in place, you'd need to use XElement.ReplaceAttributes. Otherwise, you can just remove the old ones and add new ones. (You can't modify the name of an XAttribute.)

Sample code:

using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        var xdoc = new XDocument(
            new XElement("root",
               new XElement("child1",
                   new XAttribute("NotArray", "foo"),
                   new XAttribute("Array", "bar")
               ),
               new XElement("child2",
                   new XAttribute("Array", 0),
                   new XAttribute("Y", 1)
               )
            )
        );
        Console.WriteLine("Before:");
        Console.WriteLine(xdoc);
        Console.WriteLine();

        XNamespace ns = "@Json";
        var attributesToReplace = xdoc
            .Descendants()
            .Attributes("Array")
            .ToList();
        foreach (var attribute in attributesToReplace)
        {
            var element = attribute.Parent;
            attribute.Remove();
            element.Add(new XAttribute(ns + "Array", attribute.Value));
        }
        Console.WriteLine("After:");
        Console.WriteLine(xdoc);
    }
}

Output:

Before:
<root>
  <child1 NotArray="foo" Array="bar" />
  <child2 Array="0" Y="1" />
</root>

After:
<root>
  <child1 NotArray="foo" p2:Array="bar" xmlns:p2="@Json" />
  <child2 Y="1" p2:Array="0" xmlns:p2="@Json" />
</root>

people

See more on this question at Stackoverflow