| | 1 | | namespace Songhay.Xml; |
| | 2 | |
|
| | 3 | | /// <summary> |
| | 4 | | /// Static helpers for OPML. |
| | 5 | | /// </summary> |
| | 6 | | public static class OpmlUtility |
| | 7 | | { |
| | 8 | | /// <summary> |
| | 9 | | /// Conventional namespace for OPML documents. |
| | 10 | | /// </summary> |
| | 11 | | // ReSharper disable once InconsistentNaming |
| 4 | 12 | | public static XNamespace rx => "http://songhaysystem.com/schemas/opml.xsd"; |
| | 13 | |
|
| | 14 | | /// <summary> |
| | 15 | | /// Gets the <see cref="OpmlBody"/>. |
| | 16 | | /// </summary> |
| | 17 | | /// <param name="root">The root.</param> |
| | 18 | | /// <param name="ns">The namespace.</param> |
| | 19 | | public static OpmlBody? GetBody(XContainer? root, XNamespace? ns) |
| 5 | 20 | | { |
| 5 | 21 | | if (root == null) return null; |
| | 22 | |
|
| 5 | 23 | | var data = new OpmlBody |
| 5 | 24 | | { |
| 5 | 25 | | Outlines = GetOutlines(root, ns) |
| 5 | 26 | | }; |
| | 27 | |
|
| 5 | 28 | | return data; |
| 5 | 29 | | } |
| | 30 | |
|
| | 31 | | /// <summary> |
| | 32 | | /// Gets the <see cref="OpmlDocument"/>. |
| | 33 | | /// </summary> |
| | 34 | | /// <param name="path">The path.</param> |
| | 35 | | public static OpmlDocument? GetDocument(string? path) |
| 5 | 36 | | { |
| 5 | 37 | | var xd = XDocument.Load(path!); |
| | 38 | |
|
| 5 | 39 | | XNamespace? ns = xd.Root?.GetDefaultNamespace(); |
| 8 | 40 | | if (ns != null && !string.IsNullOrWhiteSpace(ns.ToString())) return GetDocument(xd.Root, ns); |
| | 41 | |
|
| 2 | 42 | | ns = xd.Root?.GetNamespaceOfPrefix(nameof(rx)); |
| 4 | 43 | | if (ns == rx) return GetDocument(xd.Root, rx); |
| | 44 | |
|
| 0 | 45 | | return GetRawDocument(xd); |
| 5 | 46 | | } |
| | 47 | |
|
| | 48 | | /// <summary> |
| | 49 | | /// Gets the <see cref="OpmlDocument"/>. |
| | 50 | | /// </summary> |
| | 51 | | /// <param name="xml">The XML.</param> |
| | 52 | | /// <param name="ns">The ns.</param> |
| | 53 | | public static OpmlDocument? GetDocument(string? xml, XNamespace? ns) |
| 0 | 54 | | { |
| 0 | 55 | | var xd = XDocument.Parse(xml!); |
| 0 | 56 | | var opml = GetDocument(xd.Root, ns); |
| | 57 | |
|
| 0 | 58 | | return opml; |
| 0 | 59 | | } |
| | 60 | |
|
| | 61 | | /// <summary> |
| | 62 | | /// Gets the <see cref="OpmlDocument"/>. |
| | 63 | | /// </summary> |
| | 64 | | /// <param name="root">The root.</param> |
| | 65 | | /// <param name="ns">The conventional namespace.</param> |
| | 66 | | public static OpmlDocument? GetDocument(XContainer? root, XNamespace? ns) |
| 5 | 67 | | { |
| 5 | 68 | | if (root == null) return null; |
| | 69 | |
|
| 5 | 70 | | var data = new OpmlDocument |
| 5 | 71 | | { |
| 5 | 72 | | OpmlBody = GetBody(root.Element(ns.ToXName("body")!), ns), |
| 5 | 73 | | OpmlHead = GetHead(root.Element(ns.ToXName("head")!), ns) |
| 5 | 74 | | }; |
| | 75 | |
|
| 5 | 76 | | return data; |
| 5 | 77 | | } |
| | 78 | |
|
| | 79 | | /// <summary> |
| | 80 | | /// Gets the <see cref="OpmlHead"/>. |
| | 81 | | /// </summary> |
| | 82 | | /// <param name="root">The root.</param> |
| | 83 | | /// <param name="ns">The namespace.</param> |
| | 84 | | public static OpmlHead? GetHead(XContainer? root, XNamespace? ns) |
| 5 | 85 | | { |
| 5 | 86 | | if (root == null) return null; |
| | 87 | |
|
| 5 | 88 | | var ownerEmail = ns.ToXName("ownerEmail"); |
| 5 | 89 | | var ownerName = ns.ToXName("ownerName"); |
| 5 | 90 | | var title = ns.ToXName("title"); |
| 5 | 91 | | var dateCreated = ns.ToXName("dateCreated"); |
| 5 | 92 | | var dateModified = ns.ToXName("dateModified"); |
| | 93 | |
|
| 5 | 94 | | return GetHead(root, ownerEmail, ownerName, title, dateCreated, dateModified); |
| 5 | 95 | | } |
| | 96 | |
|
| | 97 | | /// <summary> |
| | 98 | | /// Gets the <see cref="OpmlOutline"/>. |
| | 99 | | /// </summary> |
| | 100 | | /// <param name="root">The root.</param> |
| | 101 | | /// <param name="ns">The namespace.</param> |
| | 102 | | public static OpmlOutline? GetOutline(XElement? root, XNamespace? ns) |
| 8568 | 103 | | { |
| 8568 | 104 | | if (root == null) return null; |
| | 105 | |
|
| 8568 | 106 | | var data = GetOutline(root); |
| 8568 | 107 | | data.Outlines = GetOutlines(root, ns); |
| | 108 | |
|
| 8568 | 109 | | return data; |
| 8568 | 110 | | } |
| | 111 | |
|
| | 112 | | /// <summary> |
| | 113 | | /// Gets the array of <see cref="OpmlOutline"/>. |
| | 114 | | /// </summary> |
| | 115 | | /// <param name="root">The root.</param> |
| | 116 | | /// <param name="ns">The namespace.</param> |
| | 117 | | public static OpmlOutline[] GetOutlines(XContainer? root, XNamespace? ns) |
| 17141 | 118 | | { |
| 17141 | 119 | | if (root == null) return Enumerable.Empty<OpmlOutline>().ToArray(); |
| | 120 | |
|
| 17141 | 121 | | var data = new List<OpmlOutline>(); |
| 17141 | 122 | | root |
| 17141 | 123 | | .Elements(ns.ToXName("outline")) |
| 17141 | 124 | | .ForEachInEnumerable(o => |
| 8568 | 125 | | { |
| 8568 | 126 | | var outline = GetOutline(o, ns); |
| 8568 | 127 | | if (outline == null) return; |
| 17141 | 128 | |
|
| 8568 | 129 | | outline.Outlines = GetOutlines(o, ns); |
| 8568 | 130 | | data.Add(outline); |
| 25709 | 131 | | }); |
| | 132 | |
|
| 17141 | 133 | | return data.ToArray(); |
| 17141 | 134 | | } |
| | 135 | |
|
| | 136 | | static OpmlBody? GetBody(XContainer? root) |
| 0 | 137 | | { |
| 0 | 138 | | if (root == null) return null; |
| | 139 | |
|
| 0 | 140 | | var data = new OpmlBody |
| 0 | 141 | | { |
| 0 | 142 | | Outlines = GetOutlines(root) |
| 0 | 143 | | }; |
| | 144 | |
|
| 0 | 145 | | return data; |
| 0 | 146 | | } |
| | 147 | |
|
| | 148 | | static OpmlHead GetHead(XContainer? root, XName? ownerEmail, XName? ownerName, XName? title, XName? dateCreated, |
| | 149 | | XName? dateModified) |
| 5 | 150 | | { |
| 5 | 151 | | var data = new OpmlHead |
| 5 | 152 | | { |
| 5 | 153 | | OwnerEmail = root?.Elements(ownerEmail).ToElementValueOrNull(), |
| 5 | 154 | | OwnerName = root?.Elements(ownerName).ToElementValueOrNull(), |
| 5 | 155 | | Title = root?.Elements(title).ToElementValueOrNull() |
| 5 | 156 | | }; |
| | 157 | |
|
| | 158 | | string? s; |
| | 159 | |
|
| 5 | 160 | | s = root?.Elements(dateCreated).ToElementValueOrNull(); |
| 10 | 161 | | if (!string.IsNullOrWhiteSpace(s)) data.DateCreated = ProgramTypeUtility.ParseRfc822DateTime(s); |
| | 162 | |
|
| 5 | 163 | | s = root?.Elements(dateModified).ToElementValueOrNull(); |
| 10 | 164 | | if (!string.IsNullOrWhiteSpace(s)) data.DateModified = ProgramTypeUtility.ParseRfc822DateTime(s); |
| | 165 | |
|
| 5 | 166 | | return data; |
| 5 | 167 | | } |
| | 168 | |
|
| | 169 | | static OpmlDocument? GetRawDocument(XContainer? root) |
| 0 | 170 | | { |
| 0 | 171 | | if (root == null) return null; |
| | 172 | |
|
| 0 | 173 | | var data = new OpmlDocument |
| 0 | 174 | | { |
| 0 | 175 | | OpmlBody = GetBody(root.Descendants("body").FirstOrDefault()), |
| 0 | 176 | | OpmlHead = GetHead(root.Descendants("head").FirstOrDefault(), "ownerEmail", "ownerName", "title", |
| 0 | 177 | | "dateCreated", "dateModified") |
| 0 | 178 | | }; |
| | 179 | |
|
| 0 | 180 | | return data; |
| 0 | 181 | | } |
| | 182 | |
|
| | 183 | | static OpmlOutline GetOutline(XElement? root) |
| 8568 | 184 | | { |
| 8568 | 185 | | var data = new OpmlOutline |
| 8568 | 186 | | { |
| 8568 | 187 | | Category = root.ToAttributeValueOrNull("category"), |
| 8568 | 188 | | Id = root.ToAttributeValueOrNull("id"), |
| 8568 | 189 | | Text = root.ToAttributeValueOrNull("text"), |
| 8568 | 190 | | Title = root.ToAttributeValueOrNull("title"), |
| 8568 | 191 | | OutlineType = root.ToAttributeValueOrNull("type"), |
| 8568 | 192 | | Url = root.ToAttributeValueOrNull("url"), |
| 8568 | 193 | | XmlUrl = root.ToAttributeValueOrNull("xmlUrl") |
| 8568 | 194 | | }; |
| | 195 | |
|
| 8568 | 196 | | if (data.Url != null) |
| 8272 | 197 | | data.Url = Environment.ExpandEnvironmentVariables(data.Url); |
| 8568 | 198 | | if (data.XmlUrl != null) |
| 0 | 199 | | data.XmlUrl = Environment.ExpandEnvironmentVariables(data.XmlUrl); |
| | 200 | |
|
| 8568 | 201 | | return data; |
| 8568 | 202 | | } |
| | 203 | |
|
| | 204 | | static OpmlOutline[] GetOutlines(XContainer? root) |
| 0 | 205 | | { |
| 0 | 206 | | if (root == null) return Enumerable.Empty<OpmlOutline>().ToArray(); |
| | 207 | |
|
| 0 | 208 | | var data = new List<OpmlOutline>(); |
| 0 | 209 | | root |
| 0 | 210 | | .Elements("outline") |
| 0 | 211 | | .ForEachInEnumerable(o => |
| 0 | 212 | | { |
| 0 | 213 | | var outline = GetOutline(o); |
| 0 | 214 | | outline.Outlines = GetOutlines(o); |
| 0 | 215 | | data.Add(outline); |
| 0 | 216 | | }); |
| | 217 | |
|
| 0 | 218 | | return data.ToArray(); |
| 0 | 219 | | } |
| | 220 | | } |