2

I have an xml document of the following format:

<body>
    <par id = "1">
      <prop type="Content">One</prop>
      <child xml:id="1">
        <span>This is span 1</span>
      </child>
      <child xml:id="2">
        <span>This is span 2</span>
      </child>
    </par>
</body>

I'm not very familiar with using LINQ, and I'd like to use it to swap the elements of the above code. (I.E., I'd like to move

<span>This is span 2</span>

into the

<child xml:id="1"></child>

element tree, and vica versa)

I'm running through the examples at http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b, but I'd really like an additional push in the right direction (I'm honestly having trouble figuring out where to start!).

Thank you!

gfppaste
  • 1,111
  • 4
  • 18
  • 48
  • Does this answer help: http://stackoverflow.com/questions/3740627/how-to-swap-two-xml-elements-in-linq-to-xml ? – Richard Morgan Jun 07 '12 at 19:22
  • I think you want LINQ to XML: http://msdn.microsoft.com/en-us/library/bb387098.aspx – devuxer Jun 07 '12 at 19:24
  • Both of those help a lot. One thing I'm not understanding... is an XDocument similar to a StreamReader? As in, will the XDocument object read the XML input line by line, or will it buffer the whole XML input and convert every element to an object, and allow direct manipulation? Basically, what I'm asking is, is swapping XElements similar to swapping variables, where you can just to x = temp, x = y, y = temp? – gfppaste Jun 07 '12 at 19:40
  • @gfppaste XDocument loads the whole thing into memory. – Richard Morgan Jun 07 '12 at 19:45

3 Answers3

1

You can select a specific elemnt using the Linq to sml Query

   var  retmodule = (from c in xdoc.Elements("body").Elements("par").Elements("child").
                             where c.Attribute("xml:id").Value == 2
                             select new 
                             {
                              c.Element("span").Value
                             }).SingleOrDefault();

and then insert it using the combination of xpath and xml library

XElement parentXElement = xmldoc.XPathSelectElement("products");
XElement refXElement = xdoc.XPathSelectElement("body/par/child [@xml:id = '2']");
XElement newXElement = new XElement("span", retmodule.ToString());
refXElement.AddAfterSelf(newXElement);
xdoc.Save();
COLD TOLD
  • 13,513
  • 3
  • 35
  • 52
  • I ended up using a combination of this solution and http://stackoverflow.com/questions/10655068/xelement-linq-code-failure – gfppaste Jun 07 '12 at 21:10
1

I believe this will do what you want:

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

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml = @"
<body>
    <par id = ""1"">
      <prop type=""Content"">One</prop>
      <child xml:id=""1"">
        <span>This is span 1</span>
      </child>
      <child xml:id=""2"">
        <span>This is span 2</span>
      </child>
    </par>
</body>";
            XDocument doc = XDocument.Parse(xml);
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.CreateNavigator().NameTable);
            namespaceManager.AddNamespace("xml", "http://www.w3.org/XML/1998/namespace");
            XElement span1 = doc.Root.XPathSelectElement(@"/body/par/child[@xml:id = ""1""]/span[1]", namespaceManager);
            XElement span2 = doc.Root.XPathSelectElement(@"/body/par/child[@xml:id = ""2""]/span[1]", namespaceManager);

            span1.ReplaceWith(span2);
            span2.ReplaceWith(span1);

            Console.WriteLine(doc);
        }
    }
}
Jeremy Pridemore
  • 1,995
  • 1
  • 14
  • 24
1

You could use LINQ, but it's really meant for querying, not modifying. Technically you could write a query to give you the results you want, but it would be fairly ugly.

I would recommend loading the string into an XMLDocument and swapping out the nodes using XPath:

    private static string swap(string xml)
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.LoadXml(xml);

        XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xDoc.NameTable);
        namespaceManager.AddNamespace("xml", "http://www.w3.org/XML/1998/namespace");  

        var node1 = xDoc.SelectSingleNode(@"//child[@xml:id=""1""]",namespaceManager);
        var node2 = xDoc.SelectSingleNode(@"//child[@xml:id=""2""]",namespaceManager);

        var temp = node1.InnerXml;
        node1.InnerXml = node2.InnerXml;
        node2.InnerXml = temp;

        return xDoc.OuterXml;
    }

Note that you'll need to account for the 'xml' namespace in your document (which I assume is defined somewhere else) by using an XmlNamespaceManager.

D Stanley
  • 149,601
  • 11
  • 178
  • 240