Pattern for parsing XML Elements of the same type under different Parent Elements?



So I'm looking to parse an XML file that could look something like this:



<Locations>
<Location Name="California">
<Location Name="Los Angeles">
<Person Name="Harrison Ford"/>
</Location>
</Location>
</Locations>

<People>
<Person Name="Jake Gyllenhaal" Location="Los Angeles"/>
</People>


So I'm building up a list of locations and people. As a business rule a 'person' must be associated with a 'location' but this can be done in one of two ways. Either by listing them as a child of a location element whereby they take on that parent location or by explicitly listing it when listed under the People element. Right now I handle it something like this (without error checking of any kind).



public class Parser
{
public void Parse(XElement xmlRoot)
{
IList<Location> locations = new List<Location>();
IList<Person> people = new List<Person>();

var locationParser = new LocationParser();

locations = locationParser.ParseLocations(xmlRoot.Element("Locations"), people);

var peopleParser = new PeopleParser();

people = peopleParser.ParsePeople(xmlRoot.Element("People"), locations);

// Do stuff with XML read objects.
}
}

public class PeopleParser
{
public IList<Person> ParsePeople(XElement peopleRoot, IList<Location> locations)
{
var xPeople = peopleRoot.Elements("Person");
var people = new List<Person>();

foreach (var person in xPeople)
{
var locationName = person.Attribute("Location").Value;

var location = locations.First(loc => loc.Name.Equals(locationName));

people.Add(this.ParsePerson(person, location));
}

return people;
}

public Person ParsePerson(XElement person, Location location)
{
var personName = person.Attribute("Name").Value;

return new Person(personName, location);
}
}

public class LocationParser
{
PeopleParser peopleParser = new PeopleParser();

public IList<Location> ParseLocations(XElement locationRoot, IList<Person> people)
{
var xLocations = locationRoot.Elements("Location");
var locations = new List<Location>();

foreach (var location in xLocations)
{
locations.Add(this.ParseLocation(location, people));
}

return locations;
}

public Location ParseLocation(XElement xLocation, IList<Person> people)
{
var children = new List<Location>();

foreach (var subLocation in xLocation.Elements("Location"))
{
children.Add(this.ParseLocation(subLocation, people));
}

var newLocation = new Location(xLocation.Attribute("Name").Value, children);

foreach (var xPerson in xLocation.Elements("Person"))
{
people.Add(peopleParser.ParsePerson(xPerson, newLocation));
}

return newLocation;
}
}
}


This code is to me 'ugly' and this is only a simple example of something that gets alot uglier as more dependent XML types are added. Is this about as good as it gets or is there a way this could be rewritten for better separation of concerns?


No comments:

Post a Comment