XDocument.LoadRootElementAsync

This commit is contained in:
ClemensFischer 2025-09-19 11:53:25 +02:00
parent fedf5eba12
commit cd40a627ce
6 changed files with 53 additions and 42 deletions

View file

@ -131,41 +131,40 @@ namespace MapControl
var docEntry = archive.GetEntry("doc.kml") ?? var docEntry = archive.GetEntry("doc.kml") ??
archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ??
throw new ArgumentException($"No KML entry found in {archiveFilePath}."); 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<List<ImageOverlay>> LoadImageOverlaysFromFile(string docFilePath) private static async Task<List<ImageOverlay>> LoadImageOverlaysFromFile(string docFilePath)
{ {
var docUri = new Uri(FilePath.GetFullPath(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<List<ImageOverlay>> LoadImageOverlays(XDocument document, Func<ImageOverlay, Task> loadFunc) private static async Task<List<ImageOverlay>> LoadImageOverlays(XElement rootElement, Func<ImageOverlay, Task> loadFunc)
{ {
var imageOverlays = ReadImageOverlays(document); var imageOverlays = ReadImageOverlays(rootElement);
await Task.WhenAll(imageOverlays.Select(loadFunc)); await Task.WhenAll(imageOverlays.Select(loadFunc));
return imageOverlays; return imageOverlays;
} }
private static List<ImageOverlay> ReadImageOverlays(XDocument document) private static List<ImageOverlay> ReadImageOverlays(XElement rootElement)
{ {
var rootElement = document.Root;
var ns = rootElement.Name.Namespace; var ns = rootElement.Name.Namespace;
var docElement = rootElement.Element(ns + "Document") ?? rootElement; var docElement = rootElement.Element(ns + "Document") ?? rootElement;
var imageOverlays = new List<ImageOverlay>(); var imageOverlays = new List<ImageOverlay>();
@ -241,14 +240,5 @@ namespace MapControl
return new LatLonBox(south, west, north, east, rotation); return new LatLonBox(south, west, north, east, rotation);
} }
private static Task<XDocument> 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
}
} }
} }

View file

@ -114,7 +114,7 @@ namespace MapControl
{ {
using var stream = await ImageLoader.HttpClient.GetStreamAsync(uri); using var stream = await ImageLoader.HttpClient.GetStreamAsync(uri);
element = XDocument.Load(stream).Root; element = await XDocument.LoadRootElementAsync(stream);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -170,7 +170,7 @@ namespace MapControl
if (ServiceUri != null && ParentMap?.MapProjection != null) if (ServiceUri != null && ParentMap?.MapProjection != null)
{ {
if (WmsLayers == 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. // Get first Layer from a GetCapabilities response.
// //

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
@ -25,25 +26,30 @@ namespace MapControl
public string UrlTemplate { get; private set; } public string UrlTemplate { get; private set; }
public List<WmtsTileMatrixSet> TileMatrixSets { get; private set; } public List<WmtsTileMatrixSet> TileMatrixSets { get; private set; }
public static async Task<WmtsCapabilities> ReadCapabilitiesAsync(Uri capabilitiesUri, string layer) public static async Task<WmtsCapabilities> 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 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") ?? var contentsElement = capabilitiesElement.Element(wmts + "Contents") ??
throw new ArgumentException("Contents element not found."); throw new ArgumentException("Contents element not found.");
@ -84,7 +90,7 @@ namespace MapControl
var style = styleElement?.Element(ows + "Identifier")?.Value ?? ""; 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 var tileMatrixSetIds = layerElement
.Elements(wmts + "TileMatrixSetLink") .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 formatPng = "image/png";
const string formatJpg = "image/jpeg"; const string formatJpg = "image/jpeg";
@ -148,14 +154,8 @@ namespace MapControl
.Select(g => g.Attribute(xlink + "href")?.Value) .Select(g => g.Attribute(xlink + "href")?.Value)
.Where(h => !string.IsNullOrEmpty(h)) .Where(h => !string.IsNullOrEmpty(h))
.Select(h => h.Split('?')[0]) .Select(h => h.Split('?')[0])
.FirstOrDefault(); .FirstOrDefault() ??
defaultUrl;
if (urlTemplate == null &&
capabilitiesUrl != null &&
capabilitiesUrl.IndexOf("Request=GetCapabilities", StringComparison.OrdinalIgnoreCase) >= 0)
{
urlTemplate = capabilitiesUrl.Split('?')[0];
}
if (urlTemplate != null) if (urlTemplate != null)
{ {
@ -254,7 +254,7 @@ namespace MapControl
string[] topLeftCornerStrings; string[] topLeftCornerStrings;
if (string.IsNullOrEmpty(valueString) || 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[0], NumberStyles.Float, CultureInfo.InvariantCulture, out double left) ||
!double.TryParse(topLeftCornerStrings[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double top)) !double.TryParse(topLeftCornerStrings[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double top))
{ {

View file

@ -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<XElement> 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;
}
}
}

View file

@ -10,6 +10,7 @@
<PackageId>XAML.MapControl.UWP</PackageId> <PackageId>XAML.MapControl.UWP</PackageId>
<Title>$(AssemblyTitle)</Title> <Title>$(AssemblyTitle)</Title>
<Description>A set of UWP controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays</Description> <Description>A set of UWP controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays</Description>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DisableRuntimeMarshalling>true</DisableRuntimeMarshalling> <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
<DefaultLanguage>en-US</DefaultLanguage> <DefaultLanguage>en-US</DefaultLanguage>
</PropertyGroup> </PropertyGroup>

View file

@ -9,6 +9,7 @@
<PackageId>XAML.MapControl.WinUI</PackageId> <PackageId>XAML.MapControl.WinUI</PackageId>
<Title>$(AssemblyTitle)</Title> <Title>$(AssemblyTitle)</Title>
<Description>A set of WinUI controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays</Description> <Description>A set of WinUI controls for rendering raster maps from different providers like OpenStreetMap and various types of map overlays</Description>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>