user360968
user360968

Reputation: 65

Linq to XML to compare strings

I'm trying to write a piece of code which receives a string, uses the data in this string to make changes to another string then saves the other string

I would prefer to do this using linq as I'm somewhat familiar with it, although that's not to say that I'm completely close minded.

Anyway, the string being received is in a form like

"<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Value><Code>AAA</Code><Description>First description</Description><Bool>Y</Bool></Value><Value><Code>BBB</Code><Description>Second description</Description><Bool>Y</Bool></Value><Value><Code>CCC</Code><Description>Third description</Description><Bool>N</Bool></Value></Root>";

or with proper formatting

    "<?xml version=\"1.0\" encoding=\"utf-8\"?>
    <Root>
        <Value>
            <Code>AAA</Code>
            <Description>First description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>BBB</Code>
            <Description>Second description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>CCC</Code>
            <Description>Third description</Description>
            <Bool>N</Bool>
        </Value>
    </Root>"

and, for example. the other value is like

    "<?xml version=\"1.0\" encoding=\"utf-8\"?>
    <Root>
        <Value>
            <Code>111</Code>
            <Description>111 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>AAA</Code>
            <Description>First description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>222</Code>
            <Description>222 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>BBB</Code>
            <Description>Second description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>333</Code>
            <Description>333 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>CCC</Code>
            <Description>Third description</Description>
            <Bool>Y</Bool>
        </Value>
    </Root>"

so of the same form but with more values and with all Bools set to Y. All I want to do is to find all the codes with a bool set to N and set those Bools on the new XML to N.

so the result of combining both of these would be the new xml but the Value with code CCC would have the Bool set as N. so:

    "<?xml version=\"1.0\" encoding=\"utf-8\"?>
    <Root>
        <Value>
            <Code>111</Code>
            <Description>111 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>AAA</Code>
            <Description>First description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>222</Code>
            <Description>222 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>BBB</Code>
            <Description>Second description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>333</Code>
            <Description>333 description</Description>
            <Bool>Y</Bool>
        </Value>
        <Value>
            <Code>CCC</Code>
            <Description>Third description</Description>
            <Bool>N</Bool>
        </Value>
    </Root>"

To me it seems as though there should be an incredibly easy way to do this using Linq to XML but I've been working at it for a while now and my inexperience with XML seems to be showing as I'm having quite a bit of trouble with this.

Any help would be much appreciated.

Thanks

Upvotes: 2

Views: 1082

Answers (3)

Meysam
Meysam

Reputation: 18137

If your first xml is stored in "doc1.xml" and the second one is stored in "doc2.xml", you can achieve your goal simply by doing this:

XElement doc1 = XElement.Load("doc1.xml");
XElement doc2 = XElement.Load("doc2.xml");

var pairs = from v1 in doc1.Elements("Value")
    join v2 in doc2.Elements("Value")
    on v1.Element("Code").Value equals v2.Element("Code").Value
    select new {v1, v2};

foreach (var pair in pairs)
    pair.v1.Element("Bool").Value = pair.v2.Element("Bool").Value;

The above code, manipulates doc1 based on doc2. You can then save the result in a new file like "doc3.xml":

doc1.Save("doc3.xml");

Upvotes: 0

Viper
Viper

Reputation: 2236

Here is another solution but its more like using linq and not doing it with linq:

string srcString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Value><Code>AAA</Code><Description>First description</Description><Bool>Y</Bool></Value><Value><Code>BBB</Code><Description>Second description</Description><Bool>Y</Bool></Value><Value><Code>CCC</Code><Description>Third description</Description><Bool>N</Bool></Value></Root>";
string targetString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Value><Code>111</Code><Description>111 description</Description><Bool>Y</Bool></Value><Value><Code>AAA</Code><Description>First description</Description><Bool>Y</Bool></Value><Value><Code>222</Code><Description>222 description</Description><Bool>Y</Bool></Value><Value><Code>BBB</Code><Description>Second description</Description><Bool>Y</Bool></Value><Value><Code>333</Code><Description>333 description</Description><Bool>Y</Bool></Value><Value><Code>CCC</Code><Description>Third description</Description><Bool>Y</Bool></Value></Root>";

XDocument srcDocument = XDocument.Parse( srcString );
XDocument targetDocument = XDocument.Parse( targetString );

// find all Value-elements with Bool = 'N' from the srcString
var srcData = from data in srcDocument.Element( "Root" ).Elements( "Value" )
              where string.Compare( data.Element( "Bool" ).Value.ToString( ), "N", true ) == 0
              select new { Code = data.Element( "Code" ).Value,
                           Description = data.Element( "Description" ).Value,
                           Bool = data.Element( "Bool" ).Value };

foreach( var item in srcData )
{
    var xmlData = from data in targetDocument.Element( "Root" ).Elements( "Value" )
                  where string.Compare( data.Element( "Code" ).Value.ToString( ), item.Code, true ) == 0
                  select data;

    foreach( var data in xmlData )
    {
        data.Element( "Bool" ).Value = "N";
    }
}

var finalString = targetDocument.ToString( );

Upvotes: 0

Konrad Morawski
Konrad Morawski

Reputation: 8394

Something like that?

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

namespace ConsoleApplication1
{
    class Program
    {
        static XElement Join(XElement xmlOne, XElement xmlTwo)
        {
            return new XElement(
                "Root",
                    xmlOne.Elements("Value").Concat(xmlTwo.Elements("Value")).GroupBy(element => element.Element("Code").Value).Select(
                        group =>
                            new XElement("Value",
                                new XElement("Code", group.First().Element("Code").Value),
                                new XElement("Description", group.First().Element("Description").Value),
                                new XElement("Bool", group.Any(elem => elem.Element("Bool").Value == "N") ? "N" : "Y"))).ToArray());

        }

        static void Main(string[] args)
        {
            var xmlOne = XElement.Parse("<?xml version=\"1.0\" encoding=\"utf-8\"?>    <Root>        <Value>            <Code>AAA</Code>            <Description>First description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>BBB</Code>            <Description>Second description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>CCC</Code>            <Description>Third description</Description>            <Bool>N</Bool>        </Value>    </Root>");
            var xmlTwo = XElement.Parse("<?xml version=\"1.0\" encoding=\"utf-8\"?>    <Root>        <Value>            <Code>111</Code>            <Description>111 description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>AAA</Code>            <Description>First description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>222</Code>            <Description>222 description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>BBB</Code>            <Description>Second description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>333</Code>            <Description>333 description</Description>            <Bool>Y</Bool>        </Value>        <Value>            <Code>CCC</Code>            <Description>Third description</Description>            <Bool>Y</Bool>        </Value>    </Root>");
            var result = Join(xmlOne, xmlTwo);
        }
    }
}

Upvotes: 2

Related Questions