-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXmlReaderExtensions.cs
122 lines (106 loc) · 4.14 KB
/
XmlReaderExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System.Xml;
namespace SmsAndMmsMerger;
/// <summary>
/// Extension methods for <see cref="XmlReader"/>
/// </summary>
public static class XmlReaderExtensions
{
/// <summary>
/// Returns the value of <paramref name="attribute"/>. If the attribute equals the literal string "null", or is null or whitespace, it'll return null
/// </summary>
public static string? GetAttributeNullable(this XmlReader reader, string attribute)
{
string? value = reader.GetAttribute(attribute);
if (string.IsNullOrWhiteSpace(value) == true)
{
return null;
}
if (value == "null")
{
return null;
}
return value;
}
/// <summary>
/// Moves the <see cref="XmlReader"/> to the next readable sibling regardless of its name.
/// </summary>
/// <param name="reader"><seealso cref="XmlReader"/> to operate on</param>
/// <returns><c>true</c> if a sibling node was found, <c>false</c> if it wasn't</returns>
public static bool ReadToNextSibling(this XmlReader reader)
{
int depth = reader.Depth;
do
{
} while ((reader.Read() == true) && (reader.Depth > depth));
if (reader.NodeType == XmlNodeType.EndElement)
{
if (reader.Read() == false)
{
return false;
}
}
return reader.Depth == depth;
}
/// <summary>
/// Reads an attribute as a <see cref="long"/> with a list of fallback attributes to read from should the first item not be a valid <see cref="long"/>
/// </summary>
/// <param name="reader"><see cref="XmlReader"/> to operate on</param>
/// <param name="primaryAttribute">Preferred name of the XML attribute to read from</param>
/// <param name="alternateAttributes">Alternate attributes to read from, if required</param>
/// <returns>Value of the first attribute with a valid value</returns>
public static long? GetAttributeAsLongWithFallback(this XmlReader reader, string primaryAttribute, params string[] alternateAttributes)
{
Func<string, long?> converter = inp =>
{
long converted;
if (long.TryParse(inp, out converted) == false)
{
return null;
}
return converted;
};
return GetAttributeWithFallback(reader, primaryAttribute, converter, alternateAttributes);
}
/// <summary>
/// Reads an attribute, of type <typeparamref name="TType"/>, with a list of fall back attributes if required
/// </summary>
/// <typeparam name="TType">Type of result</typeparam>
/// <param name="reader"><seealso cref="XmlReader"/> to operate on</param>
/// <param name="primaryAttribute">Preferred attribute name</param>
/// <param name="converter">Method for converting the string representation of the attribute to <typeparamref name="TType"/></param>
/// <param name="alternateAttributes">Fallback attributes if required</param>
/// <returns>Value of the first attribute with a valid value</returns>
public static TType? GetAttributeWithFallback<TType>(this XmlReader reader, string primaryAttribute, Func<string, TType?> converter, params string[] alternateAttributes)
{
string value = reader.GetAttributeNullable(primaryAttribute)!;
TType? converted = default(TType);
if (string.IsNullOrWhiteSpace(value) == false)
{
converted = converter(value);
if (converted != null)
{
return converted;
}
}
foreach (string alternate in alternateAttributes)
{
value = reader.GetAttribute(alternate)!;
if (string.IsNullOrWhiteSpace(value) == false)
{
converted = converter(value);
if (converted != null)
{
return converted;
}
}
}
return default;
}
/// <summary>
/// Gets an <seealso cref="IXmlLineInfo"/> from the <paramref name="reader"/>
/// </summary>
public static IXmlLineInfo AsLineInfo(this XmlReader reader)
{
return reader as IXmlLineInfo ?? throw new ArgumentException($"{nameof(reader)} cannot be cast to {nameof(IXmlLineInfo)}");
}
}