What am I doing wrong with LINQ and XML

B

Bernard

I have an xml fragment that looks like this assigned to doc variable:
<charge_details>
<charge>
<type>Maintenance Charge</type>
<currency>GBP</currency>
<percentage>0.35000</percentage>
<frequency>Monthly</frequency>
<term>31</term>
<lower_bound>500000.00</lower_bound>
<upper_bound>999999.99</upper_bound>
</charge>
<charge>
<type>Maintenance Charge</type>
<currency>GBP</currency>
<percentage>0.35000</percentage>
<frequency>Monthly</frequency>
<term>31</term>
<lower_bound>500000.00</lower_bound>
<upper_bound>999999.99</upper_bound>
</charge>
<charge>
<type>Quarterly Admin Charge</type>
<currency>GBP</currency>
<percentage>22.00000</percentage>
<frequency />
</charge>
<charge>
<type>Dealing Settlement Charge</type>
<currency>GBP</currency>
<charge_amount>22.00</charge_amount>
<frequency />
</charge>
</charge_details>

I have a LINQ query that looks like this:
IList<PolicyTerm> policyTerms = (from MMPPolicyTerms in
doc.Elements("charge_details").Elements("charge")
select new PolicyTerm
{
PolicyTermType =
(PolicyTermType)(StringEnum.Parse(typeof(PolicyTermType),
MMPPolicyTerms.Element("type").Value)),
Percentage = (double?)MMPPolicyTerms.Element("percentage") ??
0.00,
Currency = (string)MMPPolicyTerms.Element("currency") ??
string.Empty,
Amount = (double?)MMPPolicyTerms.Element("charge_amount") ??
0.00,
Term = (string)MMPPolicyTerms.Element("term") ?? string.Empty
}).ToList();

And I keep getting an exception being thrown...I'm assuming because some of
the nodes aren't always there?
I thought I would be able to get around it by using the ?? operator.

The class PolicyTerm is asimple one that looks like this:
public class PolicyTerm
{
public PolicyTermType PolicyTermType { get; set; }
public double? Percentage { get; set; }
public double? Amount { get; set; }
public string Currency { get; set; }
public string Term { get; set; }
}


Does anyone have any suggestions as to what I can do to avoid this? I know I
can choose not to use ToList but then I just get the error thrown when I
enumerate when I bind on the front end :(
 
M

Marc Vangrieken

I have an xml fragment that looks like this assigned to doc variable:
<charge_details>
<charge>
<type>Maintenance Charge</type>
<currency>GBP</currency>
<percentage>0.35000</percentage>
<frequency>Monthly</frequency>
<term>31</term>
<lower_bound>500000.00</lower_bound>
<upper_bound>999999.99</upper_bound>
</charge>
<charge>
<type>Maintenance Charge</type>
<currency>GBP</currency>
<percentage>0.35000</percentage>
<frequency>Monthly</frequency>
<term>31</term>
<lower_bound>500000.00</lower_bound>
<upper_bound>999999.99</upper_bound>
</charge>
<charge>
<type>Quarterly Admin Charge</type>
<currency>GBP</currency>
<percentage>22.00000</percentage>
<frequency />
</charge>
<charge>
<type>Dealing Settlement Charge</type>
<currency>GBP</currency>
<charge_amount>22.00</charge_amount>
<frequency />
</charge>
</charge_details>

I have a LINQ query that looks like this:
IList<PolicyTerm> policyTerms = (from MMPPolicyTerms in
doc.Elements("charge_details").Elements("charge")
select new PolicyTerm
{
PolicyTermType =
(PolicyTermType)(StringEnum.Parse(typeof(PolicyTermType),
MMPPolicyTerms.Element("type").Value)),
Percentage = (double?)MMPPolicyTerms.Element("percentage") ??
0.00,
Currency = (string)MMPPolicyTerms.Element("currency") ??
string.Empty,
Amount = (double?)MMPPolicyTerms.Element("charge_amount") ??
0.00,
Term = (string)MMPPolicyTerms.Element("term") ?? string.Empty
}).ToList();

And I keep getting an exception being thrown...I'm assuming because some of
the nodes aren't always there?
I thought I would be able to get around it by using the ?? operator.
Hi Bernard,

Interesting question. Which exception are you getting?

Kind regards
Marc Vangrieken
http://vangrieken.wordpress.com
 
B

Bernard

Object not found exception or the Exception has been thrown by the target of
an invocation, depending on whether I do ToList or not.
 
M

Martin Honnen

Bernard said:
And I keep getting an exception being thrown...I'm assuming because some of
the nodes aren't always there?
I thought I would be able to get around it by using the ?? operator.

The class PolicyTerm is asimple one that looks like this:
public class PolicyTerm
{
public PolicyTermType PolicyTermType { get; set; }

Can you show us your definition of PolicyTermType? And please tell us
exactly which exception you get.
I took your XML and your C# code with the exeception of lines dealing
with the PolicyTermType and was able to compile and run it just fine.
 
M

Martin Honnen

Bernard said:
Object not found exception or the Exception has been thrown by the target of
an invocation, depending on whether I do ToList or not.

How do you create the variable 'doc'?
Make sure you do
XDocument doc = XDocument.Load("file.xml");
 
B

Bernard

Here is the enum
public enum PolicyTermType
{
[StringValue("Charging Structure")]CHARGING_STRUCTURE = 1,
[StringValue("Maintenance Charge")]MAINTENANCE_CHARGE = 2,
[StringValue("Portofolio Charge")]PORTFOLIO_CHARGE = 3,
[StringValue("Establishment Charge")]ESTABLISHMENT_CHARGE = 4,
[StringValue("Allocation Rate")]ALLOCATION_RATE = 5,
[StringValue("Quarterly Admin Charge")]QUARTERLY_ADMIN_CHARGE = 6,
[StringValue("Surrender Charges")]SURRENDER_CHARGES = 7,
[StringValue("Custodian Fees")]CUSTODIAN_FEES = 8,
[StringValue("Explicity Renewal Comission
Fee")]EXPLICIT_RENEWAL_COMMISSION_FEE = 9,
[StringValue("Investment Manager Fee")]INVESTMENT_MANAGER_FEE = 10,
[StringValue("Investment Advisor Fee")]INVESTMENT_ADVISER_FEE = 11
};

Here is the string enum:


using System;
using System.Collections;
using System.Reflection;

namespace TestBus
{

#region Class StringEnum

/// <summary>
/// Helper class for working with 'extended' enums using <see
cref="StringValueAttribute"/> attributes.
/// </summary>
public class StringEnum
{
#region Instance implementation

private Type _enumType;
private static Hashtable _stringValues = new Hashtable();

/// <summary>
/// Creates a new <see cref="StringEnum"/> instance.
/// </summary>
/// <param name="enumType">Enum type.</param>
public StringEnum(Type enumType)
{
if (!enumType.IsEnum)
throw new ArgumentException(String.Format("Supplied type must be an
Enum. Type was {0}", enumType.ToString()));

_enumType = enumType;
}

/// <summary>
/// Gets the string value associated with the given enum value.
/// </summary>
/// <param name="valueName">Name of the enum value.</param>
/// <returns>String Value</returns>
public string GetStringValue(string valueName)
{
Enum enumType;
string stringValue = null;
try
{
enumType = (Enum) Enum.Parse(_enumType, valueName);
stringValue = GetStringValue(enumType);
}
catch (Exception) { }//Swallow!

return stringValue;
}

/// <summary>
/// Gets the string values associated with the enum.
/// </summary>
/// <returns>String value array</returns>
public Array GetStringValues()
{
ArrayList values = new ArrayList();
//Look for our string value associated with fields in this enum
foreach (FieldInfo fi in _enumType.GetFields())
{
//Check for our custom attribute
StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof
(StringValueAttribute), false) as StringValueAttribute[];
if (attrs.Length > 0)
values.Add(attrs[0].Value);

}

return values.ToArray();
}

/// <summary>
/// Gets the values as a 'bindable' list datasource.
/// </summary>
/// <returns>IList for data binding</returns>
public IList GetListValues()
{
Type underlyingType = Enum.GetUnderlyingType(_enumType);
ArrayList values = new ArrayList();
//Look for our string value associated with fields in this enum
foreach (FieldInfo fi in _enumType.GetFields())
{
//Check for our custom attribute
StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof
(StringValueAttribute), false) as StringValueAttribute[];
if (attrs.Length > 0)
values.Add(new DictionaryEntry(Convert.ChangeType(Enum.Parse(_enumType,
fi.Name), underlyingType), attrs[0].Value));

}

return values;

}

/// <summary>
/// Return the existence of the given string value within the enum.
/// </summary>
/// <param name="stringValue">String value.</param>
/// <returns>Existence of the string value</returns>
public bool IsStringDefined(string stringValue)
{
return Parse(_enumType, stringValue) != null;
}

/// <summary>
/// Return the existence of the given string value within the enum.
/// </summary>
/// <param name="stringValue">String value.</param>
/// <param name="ignoreCase">Denotes whether to conduct a case-insensitive
match on the supplied string value</param>
/// <returns>Existence of the string value</returns>
public bool IsStringDefined(string stringValue, bool ignoreCase)
{
return Parse(_enumType, stringValue, ignoreCase) != null;
}

/// <summary>
/// Gets the underlying enum type for this instance.
/// </summary>
/// <value></value>
public Type EnumType
{
get { return _enumType; }
}

#endregion

#region Static implementation

/// <summary>
/// Gets a string value for a particular enum value.
/// </summary>
/// <param name="value">Value.</param>
/// <returns>String Value associated via a <see
cref="StringValueAttribute"/> attribute, or null if not found.</returns>
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();

if (_stringValues.ContainsKey(value))
output = (_stringValues[value] as StringValueAttribute).Value;
else
{
//Look for our 'StringValueAttribute' in the field's custom attributes
FieldInfo fi = type.GetField(value.ToString());
StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof
(StringValueAttribute), false) as StringValueAttribute[];
if (attrs.Length > 0)
{
_stringValues.Add(value, attrs[0]);
output = attrs[0].Value;
}

}
return output;

}

/// <summary>
/// Parses the supplied enum and string value to find an associated enum
value (case sensitive).
/// </summary>
/// <param name="type">Type.</param>
/// <param name="stringValue">String value.</param>
/// <returns>Enum value associated with the string value, or null if not
found.</returns>
public static object Parse(Type type, string stringValue)
{
return Parse(type, stringValue, false);
}

/// <summary>
/// Parses the supplied enum and string value to find an associated enum
value.
/// </summary>
/// <param name="type">Type.</param>
/// <param name="stringValue">String value.</param>
/// <param name="ignoreCase">Denotes whether to conduct a case-insensitive
match on the supplied string value</param>
/// <returns>Enum value associated with the string value, or null if not
found.</returns>
public static object Parse(Type type, string stringValue, bool ignoreCase)
{
object output = null;
string enumStringValue = null;

if (!type.IsEnum)
throw new ArgumentException(String.Format("Supplied type must be an
Enum. Type was {0}", type.ToString()));

//Look for our string value associated with fields in this enum
foreach (FieldInfo fi in type.GetFields())
{
//Check for our custom attribute
StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof
(StringValueAttribute), false) as StringValueAttribute[];
if (attrs.Length > 0)
enumStringValue = attrs[0].Value;

//Check for equality then select actual enum value.
if (string.Compare(enumStringValue, stringValue, ignoreCase) == 0)
{
output = Enum.Parse(type, fi.Name);
break;
}
}

return output;
}

/// <summary>
/// Return the existence of the given string value within the enum.
/// </summary>
/// <param name="stringValue">String value.</param>
/// <param name="enumType">Type of enum</param>
/// <returns>Existence of the string value</returns>
public static bool IsStringDefined(Type enumType, string stringValue)
{
return Parse(enumType, stringValue) != null;
}

/// <summary>
/// Return the existence of the given string value within the enum.
/// </summary>
/// <param name="stringValue">String value.</param>
/// <param name="enumType">Type of enum</param>
/// <param name="ignoreCase">Denotes whether to conduct a case-insensitive
match on the supplied string value</param>
/// <returns>Existence of the string value</returns>
public static bool IsStringDefined(Type enumType, string stringValue, bool
ignoreCase)
{
return Parse(enumType, stringValue, ignoreCase) != null;
}

#endregion
}

#endregion

#region Class StringValueAttribute

/// <summary>
/// Simple attribute class for storing String Values
/// </summary>
public class StringValueAttribute : Attribute
{
private string _value;

/// <summary>
/// Creates a new <see cref="StringValueAttribute"/> instance.
/// </summary>
/// <param name="value">Value.</param>
public StringValueAttribute(string value)
{
_value = value;
}

/// <summary>
/// Gets the value.
/// </summary>
/// <value></value>
public string Value
{
get { return _value; }
}
}

#endregion
}
 
M

Martin Honnen

Bernard said:
Here is the enum
public enum PolicyTermType
{
[StringValue("Charging Structure")]CHARGING_STRUCTURE = 1,
[StringValue("Maintenance Charge")]MAINTENANCE_CHARGE = 2,
[StringValue("Portofolio Charge")]PORTFOLIO_CHARGE = 3,
[StringValue("Establishment Charge")]ESTABLISHMENT_CHARGE = 4,
[StringValue("Allocation Rate")]ALLOCATION_RATE = 5,
[StringValue("Quarterly Admin Charge")]QUARTERLY_ADMIN_CHARGE = 6,
[StringValue("Surrender Charges")]SURRENDER_CHARGES = 7,
[StringValue("Custodian Fees")]CUSTODIAN_FEES = 8,
[StringValue("Explicity Renewal Comission
Fee")]EXPLICIT_RENEWAL_COMMISSION_FEE = 9,
[StringValue("Investment Manager Fee")]INVESTMENT_MANAGER_FEE = 10,
[StringValue("Investment Advisor Fee")]INVESTMENT_ADVISER_FEE = 11
};

see answer in the XML forum:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3129037&SiteID=1
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top