From cd40a627cec2a22b772e8a1db44f7ad61179575f Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Fri, 19 Sep 2025 11:53:25 +0200 Subject: [PATCH] XDocument.LoadRootElementAsync --- MapControl/Shared/GroundOverlay.cs | 32 +++++++------------- MapControl/Shared/WmsImageLayer.cs | 4 +-- MapControl/Shared/WmtsCapabilities.cs | 38 ++++++++++++------------ MapControl/Shared/XDocument.cs | 19 ++++++++++++ MapControl/UWP/MapControl.UWP.csproj | 1 + MapControl/WinUI/MapControl.WinUI.csproj | 1 + 6 files changed, 53 insertions(+), 42 deletions(-) create mode 100644 MapControl/Shared/XDocument.cs diff --git a/MapControl/Shared/GroundOverlay.cs b/MapControl/Shared/GroundOverlay.cs index 3204efb9..d650c02d 100644 --- a/MapControl/Shared/GroundOverlay.cs +++ b/MapControl/Shared/GroundOverlay.cs @@ -131,41 +131,40 @@ namespace MapControl var docEntry = archive.GetEntry("doc.kml") ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ?? throw new ArgumentException($"No KML entry found in {archiveFilePath}."); - XDocument document; + XElement element; - using (var docStream = docEntry.Open()) + using (var stream = docEntry.Open()) { - document = await LoadXDocument(docStream); + element = await XDocument.LoadRootElementAsync(stream); } - return await LoadImageOverlays(document, imageOverlay => imageOverlay.LoadImage(archive)); + return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(archive)); } private static async Task> LoadImageOverlaysFromFile(string docFilePath) { var docUri = new Uri(FilePath.GetFullPath(docFilePath)); - XDocument document; + XElement element; - using (var docStream = File.OpenRead(docUri.AbsolutePath)) + using (var stream = File.OpenRead(docUri.AbsolutePath)) { - document = await LoadXDocument(docStream); + element = await XDocument.LoadRootElementAsync(stream); } - return await LoadImageOverlays(document, imageOverlay => imageOverlay.LoadImage(docUri)); + return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(docUri)); } - private static async Task> LoadImageOverlays(XDocument document, Func loadFunc) + private static async Task> LoadImageOverlays(XElement rootElement, Func loadFunc) { - var imageOverlays = ReadImageOverlays(document); + var imageOverlays = ReadImageOverlays(rootElement); await Task.WhenAll(imageOverlays.Select(loadFunc)); return imageOverlays; } - private static List ReadImageOverlays(XDocument document) + private static List ReadImageOverlays(XElement rootElement) { - var rootElement = document.Root; var ns = rootElement.Name.Namespace; var docElement = rootElement.Element(ns + "Document") ?? rootElement; var imageOverlays = new List(); @@ -241,14 +240,5 @@ namespace MapControl return new LatLonBox(south, west, north, east, rotation); } - - private static Task LoadXDocument(Stream docStream) - { -#if NETFRAMEWORK - return Task.Run(() => XDocument.Load(docStream, LoadOptions.None)); -#else - return XDocument.LoadAsync(docStream, LoadOptions.None, System.Threading.CancellationToken.None); -#endif - } } } diff --git a/MapControl/Shared/WmsImageLayer.cs b/MapControl/Shared/WmsImageLayer.cs index 4c00731c..4e962b32 100644 --- a/MapControl/Shared/WmsImageLayer.cs +++ b/MapControl/Shared/WmsImageLayer.cs @@ -114,7 +114,7 @@ namespace MapControl { using var stream = await ImageLoader.HttpClient.GetStreamAsync(uri); - element = XDocument.Load(stream).Root; + element = await XDocument.LoadRootElementAsync(stream); } catch (Exception ex) { @@ -170,7 +170,7 @@ namespace MapControl if (ServiceUri != null && ParentMap?.MapProjection != null) { if (WmsLayers == null && - ServiceUri.ToString().IndexOf("LAYERS=", StringComparison.OrdinalIgnoreCase) < 0) + ServiceUri.OriginalString.IndexOf("LAYERS=", StringComparison.OrdinalIgnoreCase) < 0) { // Get first Layer from a GetCapabilities response. // diff --git a/MapControl/Shared/WmtsCapabilities.cs b/MapControl/Shared/WmtsCapabilities.cs index 2ee26f5c..c71b344f 100644 --- a/MapControl/Shared/WmtsCapabilities.cs +++ b/MapControl/Shared/WmtsCapabilities.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; @@ -25,25 +26,30 @@ namespace MapControl public string UrlTemplate { get; private set; } public List TileMatrixSets { get; private set; } - public static async Task ReadCapabilitiesAsync(Uri capabilitiesUri, string layer) + public static async Task ReadCapabilitiesAsync(Uri uri, string layer) { - WmtsCapabilities capabilities; + Stream xmlStream; + string defaultUrl = null; - if (capabilitiesUri.IsAbsoluteUri && (capabilitiesUri.Scheme == "http" || capabilitiesUri.Scheme == "https")) + if (uri.IsAbsoluteUri && (uri.Scheme == "http" || uri.Scheme == "https")) { - using var stream = await ImageLoader.HttpClient.GetStreamAsync(capabilitiesUri); + defaultUrl = uri.OriginalString.Split('?')[0]; - capabilities = ReadCapabilities(XDocument.Load(stream).Root, layer, capabilitiesUri.ToString()); + xmlStream = await ImageLoader.HttpClient.GetStreamAsync(uri); } else { - capabilities = ReadCapabilities(XDocument.Load(capabilitiesUri.ToString()).Root, layer, null); + xmlStream = File.OpenRead(uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString); } - return capabilities; + using var stream = xmlStream; + + var element = await XDocument.LoadRootElementAsync(stream); + + return ReadCapabilities(element, layer, defaultUrl); } - public static WmtsCapabilities ReadCapabilities(XElement capabilitiesElement, string layer, string capabilitiesUrl) + public static WmtsCapabilities ReadCapabilities(XElement capabilitiesElement, string layer, string defaultUrl) { var contentsElement = capabilitiesElement.Element(wmts + "Contents") ?? throw new ArgumentException("Contents element not found."); @@ -84,7 +90,7 @@ namespace MapControl var style = styleElement?.Element(ows + "Identifier")?.Value ?? ""; - var urlTemplate = ReadUrlTemplate(capabilitiesElement, layerElement, layer, style, capabilitiesUrl); + var urlTemplate = ReadUrlTemplate(capabilitiesElement, layerElement, layer, style, defaultUrl); var tileMatrixSetIds = layerElement .Elements(wmts + "TileMatrixSetLink") @@ -111,7 +117,7 @@ namespace MapControl }; } - public static string ReadUrlTemplate(XElement capabilitiesElement, XElement layerElement, string layer, string style, string capabilitiesUrl) + public static string ReadUrlTemplate(XElement capabilitiesElement, XElement layerElement, string layer, string style, string defaultUrl) { const string formatPng = "image/png"; const string formatJpg = "image/jpeg"; @@ -148,14 +154,8 @@ namespace MapControl .Select(g => g.Attribute(xlink + "href")?.Value) .Where(h => !string.IsNullOrEmpty(h)) .Select(h => h.Split('?')[0]) - .FirstOrDefault(); - - if (urlTemplate == null && - capabilitiesUrl != null && - capabilitiesUrl.IndexOf("Request=GetCapabilities", StringComparison.OrdinalIgnoreCase) >= 0) - { - urlTemplate = capabilitiesUrl.Split('?')[0]; - } + .FirstOrDefault() ?? + defaultUrl; if (urlTemplate != null) { @@ -254,7 +254,7 @@ namespace MapControl string[] topLeftCornerStrings; if (string.IsNullOrEmpty(valueString) || - (topLeftCornerStrings = valueString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)).Length < 2 || + (topLeftCornerStrings = valueString.Split([' '], StringSplitOptions.RemoveEmptyEntries)).Length < 2 || !double.TryParse(topLeftCornerStrings[0], NumberStyles.Float, CultureInfo.InvariantCulture, out double left) || !double.TryParse(topLeftCornerStrings[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double top)) { diff --git a/MapControl/Shared/XDocument.cs b/MapControl/Shared/XDocument.cs new file mode 100644 index 00000000..4a090fda --- /dev/null +++ b/MapControl/Shared/XDocument.cs @@ -0,0 +1,19 @@ +using System.IO; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace MapControl +{ + internal static class XDocument + { + public static async Task LoadRootElementAsync(Stream stream) + { +#if NETFRAMEWORK + var document = await Task.Run(() => System.Xml.Linq.XDocument.Load(stream, LoadOptions.None)); +#else + var document = await System.Xml.Linq.XDocument.LoadAsync(stream, LoadOptions.None, System.Threading.CancellationToken.None); +#endif + return document.Root; + } + } +} diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index 846db92e..62150d4f 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -10,6 +10,7 @@ XAML.MapControl.UWP $(AssemblyTitle) A set of UWP controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays + true true en-US diff --git a/MapControl/WinUI/MapControl.WinUI.csproj b/MapControl/WinUI/MapControl.WinUI.csproj index 53b8662a..d39fa90d 100644 --- a/MapControl/WinUI/MapControl.WinUI.csproj +++ b/MapControl/WinUI/MapControl.WinUI.csproj @@ -9,6 +9,7 @@ XAML.MapControl.WinUI $(AssemblyTitle) A set of WinUI controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays + true