开发者

C# LINQ to XML query with duplicate element names that have attributes

        <Party id="Party_1">
            <PartyTypeCode tc="1">Person</PartyTypeCode>
            <FullName>John Doe</FullName>
            <GovtID>123456789</GovtID>
            <GovtIDTC tc="1">Social Security Number US</GovtIDTC>
            <ResidenceState tc="35">New Jersey</ResidenceState>
            <Person>
                <FirstName>Frank</FirstName>
                <MiddleName>Roberts</MiddleName>
                <LastName>Madison</LastName>                    
                <Prefix>Dr.</Prefix>
                <Suffix>III</Suffix>
                <Gender tc="1">Male</Gender>
                <BirthDate>1974-01-01</BirthDate>
                <Age>35</Age>
                <Citizenship tc="1">United States of America</Citizenship>
            </Person>
            <Address>
                <AddressTypeCode tc="26">Bill Mailing</AddressTypeCode>
                <Line1>2400 Meadow Lane</Line1>
                <Line2></Line2>
                <Line3></Line3>
                <Line4></Line4>
                <City>Somerset</City>
                <AddressStateTC tc="35">New Jersey</AddressStateTC>
                <Zip>07457</Zip>
                <AddressCountryTC tc="1">United States of America</AddressCountryTC>
            </Address>
        </Party>
        <!-- ***********************  -->
        <!--  Insured Information     -->
        <!-- ***********************  -->
        <Party id="Party_2">
            <PartyTypeCode tc="1">Person</PartyTypeCode>
            <FullName>Dollie Robert Madison</FullName>
            <GovtID>123956239</GovtID>
            <GovtIDTC tc="1">Social Security Number US</GovtIDTC>
  开发者_如何学编程          <Person>
                <FirstName>Dollie</FirstName>
                <MiddleName>R</MiddleName>
                <LastName>Madison</LastName>
                <Suffix>III</Suffix>
                <Gender tc="2">Female</Gender>
                <BirthDate>1996-10-12</BirthDate>
                <Citizenship tc="1">United States of America</Citizenship>
            </Person>
            <!-- Insured Address -->
            <Address>
                <AddressTypeCode tc="26">Bill Mailing</AddressTypeCode>
                <Line1>2400 Meadow Lane</Line1>
                <City>Somerset</City>
                <AddressStateTC tc="35">New Jersey</AddressStateTC>
                <Zip>07457</Zip>
                <AddressCountryTC tc="1">United States of America</AddressCountryTC>
            </Address>
            <Risk>
                <!-- Disability Begin Effective Date -->
                <DisabilityEffectiveStartDate>2006-01-01</DisabilityEffectiveStartDate>
                <!-- Disability End Effective Date -->
                <DisabilityEffectiveStopDate>2008-01-01</DisabilityEffectiveStopDate>
            </Risk>
        </Party>
        <!-- *******************************  -->
        <!--  Company Information     -->
        <!-- ******************************  -->
        <Party id="Party_3">
            <PartyTypeCode tc="2">Organization</PartyTypeCode>
            <Organization>
                <DTCCMemberCode>1234</DTCCMemberCode>
            </Organization>
            <Carrier>
                <CarrierCode>105</CarrierCode>
            </Carrier>
        </Party>

Here is my code which doesn't work because party 3 doesn't contain FullName, I know that partyelements contains 3 parties if I only return the name attribute. Is there a way to loop through each tag seperate?

        var partyElements = from party in xmlDoc.Descendants("Party")
           select new
           {
               Name = party.Attribute("id").Value,
               PartyTypeCode = party.Element("PartyTypeCode").Value,
               FullName = party.Element("FullName").Value,
               GovtID = party.Element("GovtID").Value,
           };


How about something along these lines? (more of an idea/suggestion than an implementation, because I don't know your object model)

var parties = xmlDoc.Descendants("Party");
foreach(var party in parties)
{
    int partyTypeCode = party.Element("PartyTypeCode").Value;
    if(partyTypeCode == 1)
    {
        var person = personFactory.Build(party);
        // do something
    }
    else if(partyTypeCode == 2)
    {
        var organization = companyFactory.Build(party);
        // do something
    }
}

In a perfectly polymorphic world, you'd just have a PartyFactory and no if or switch statements, but a person party and a company party are quite different.


To avoid a NullReferenceException when accessing the FullName element you can cast it to a string without calling Value on the element. If it doesn't exist null will be returned, otherwise the value will be returned. You can then check for null while iterating over the results.

Change: FullName = party.Element("FullName").Value,

To: FullName = (string)party.Element("FullName"),

The updated query would be:

var partyElements = from party in xmlDoc.Descendants("Party")
    select new
    {
        Name = party.Attribute("id").Value,
        PartyTypeCode = party.Element("PartyTypeCode").Value,
        FullName = (string)party.Element("FullName"),
        GovtID = party.Element("GovtID").Value,
    };

You can do the same thing for all elements that may or may not exist for certain items.


I feel Ahmed's solution is the way to go. But here is the hack I came up with. If 'FullName' is the only distinguishing Element between two different types of party nodes then I guess the following may work:

var validParty = xElement.Descendants("Party")
                            .Elements().Where(x => x.Name == "FullName")
                            .Ancestors("Party")
                            .Elements().Where(x => x.Name == "PartyTypeCode")
                            .Ancestors("Party");


 var partyElements = from party in validParty 
            select new
            {
                Name = party.Attribute("id").Value,
                PartyTypeCode = party.Element("PartyTypeCode").Value,
                FullName = party.Element("FullName").Value,
                GovtID = party.Element("GovtID").Value,
            }; 

You may add additional distinguishing nodes if any like the "PartyTypeCode". I am not sure about the performance aspect of this.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜