Reputation: 1234
I have a program that parses an XML input file. The XML is somewhat busted. I did not develop the schema nor do I have control over the programs that generate the XML. Here is a sample of the XML I am having issues with.
<object type="vdisk" >
<property name="mdisk_grp_id" value="many" />
<property name="mdisk_grp_name" value="many" />
<property name="mdisk_grp_id" value="10" />
<property name="mdisk_grp_name" value="VMAX5161" />
</object>
The problem is the multiple properties of the same name. Obviously this is incorrect. I need to select the one that doesn't have "many" as a value. Right now my program grabs that because it occurs first. It breaks other things in the program. Here is what I tried, among other things. This is a partial listing of the constructor for my VDisk class. It seems to work on some of the objects of type "vdisk" in the input file but not others.
public VDisk(XElement element)
{
var mdg = from mdgs in element.Descendants("property")
where
mdgs.Attribute("name").Value == "mdisk_grp_name"
select mdgs;
foreach (XElement mdgp in mdg)
{
if (mdgp.Attribute("value").Value != "many")
{
MDiskGrpName = mdgp.Attribute("value").Value;
break;
}
}
}
Here's the code that throws the exception. there aren't any MDiskGroups actually named "many". So the var comes back empty. I could catch an exception and continue, but I want to get the correct data into the VDisk MDiskGroupName attribute.
var mdiskgrp = CurrentCluster.MDiskGroups.Where(mdg => mdg.Name == vdisk.MDiskGrpName);
mdiskgrp.FirstOrDefault().VDiskList.Add(vdisk);
Upvotes: 0
Views: 113
Reputation: 163458
You're trying to do to much in one program. Break the task up into a pipeline of simple tasks. If you want to get rid of every property with a given name except the last, do that as a preprocessing transformation. It's only a few lines of code, and separating it means the code is reusable because it can be inserted into any pipeline that uses this XML input, rather than cluttering up your "business" logic. The transformation is essentially this:
<xsl:template match="object">
<xsl:copy>
<xsl:copy select="@*"/>
<xsl:for-each-group select="Property" group-by="@name">
<xsl:copy-of select="current-group()[last()]"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
Upvotes: 0
Reputation: 4166
Try this:
element.Descendants("property").Where(x => x.Attribute("name").Value == "mdisk_grp_name" && x.Attribute("value").Value != "many").First();
Upvotes: 1