Beispiel #1
0
        public void TimestampsShouldBeWrittenInGivenTimeZone()
        {
            const string GpxText        = @"
<gpx xmlns='http://www.topografix.com/GPX/1/1' version='1.1' creator='airbreather'>
    <metadata>
        <time>1234-05-06T07:08:09</time>
    </metadata>
    <wpt lat='0.1' lon='2.3'>
        <time>5432-10-10T11:22:33</time>
    </wpt>
</gpx>
";
            var          outputTimeZone = TimeZoneInfo.CreateCustomTimeZone("meh", TimeSpan.FromHours(3.5), "meh", "meh");
            var          settings       = new GpxWriterSettings {
                TimeZoneInfo = outputTimeZone
            };
            string text = GpxFile.Parse(GpxText, null).BuildString(settings);

            // we read in times assuming UTC, and then asked it to write them out in a time zone
            // that's at +3.5 hours from UTC, so we should see +3.5 from what's written, *AND* with
            // an offset (at least at the time of writing, we always write out the most unambiguous
            // times that it seems like the framework allows).
            Assert.Contains("1234-05-06T10:38:09+03:30", text);
            Assert.Contains("5432-10-10T14:52:33+03:30", text);
        }
Beispiel #2
0
 /// <summary>
 /// Writes the given features to an <see cref="XmlWriter"/>.
 /// </summary>
 /// <param name="writer">
 /// The <see cref="XmlWriter"/> to write to.
 /// </param>
 /// <param name="settings">
 /// The <see cref="GpxWriterSettings"/> instance to use to control how GPX instances get
 /// written out, or <c>null</c> to use a general-purpose default.
 /// </param>
 /// <param name="metadata">
 /// The <see cref="GpxMetadata"/> instance that includes metadata about the file.  Required.
 /// </param>
 /// <param name="waypointFeatures">
 /// The <see cref="IFeature"/>s that include the top-level wpt instances.  Optional, but if
 /// specified, each must be an <see cref="IPoint"/> feature.
 /// </param>
 /// <param name="routeFeatures">
 /// The <see cref="IFeature"/>s that include the top-level rte instances.  Optional, but if
 /// specified, each must be an <see cref="ILineString"/> feature.
 /// </param>
 /// <param name="trackFeatures">
 /// The <see cref="IFeature"/>s that include the top-level trk instances.  Optional, but if
 /// specified, each must be an <see cref="IMultiLineString"/> feature.
 /// </param>
 /// <param name="extensions">
 /// The top-level extension data.  Optional.
 /// </param>
 public static void Write(XmlWriter writer, GpxWriterSettings settings, GpxMetadata metadata, IEnumerable <IFeature> waypointFeatures, IEnumerable <IFeature> routeFeatures, IEnumerable <IFeature> trackFeatures, object extensions) =>
 Write(writer,
       settings,
       metadata,
       waypointFeatures?.Select(NetTopologySuiteGpxFeatureConverter.ToGpxWaypoint),
       routeFeatures?.Select(NetTopologySuiteGpxFeatureConverter.ToGpxRoute),
       trackFeatures?.Select(NetTopologySuiteGpxFeatureConverter.ToGpxTrack),
       extensions);
Beispiel #3
0
        /// <summary>
        /// Writes the given features to an <see cref="XmlWriter"/>.
        /// </summary>
        /// <param name="writer">
        /// The <see cref="XmlWriter"/> to write to.
        /// </param>
        /// <param name="settings">
        /// The <see cref="GpxWriterSettings"/> instance to use to control how GPX instances get
        /// written out, or <c>null</c> to use a general-purpose default.
        /// </param>
        /// <param name="metadata">
        /// The <see cref="GpxMetadata"/> instance that includes metadata about the file.  Required.
        /// </param>
        /// <param name="features">
        /// The <see cref="IFeature"/>s to write out.  Required.
        /// </param>
        /// <param name="extensions">
        /// The top-level extension data.  Optional.
        /// </param>
        /// <remarks>
        /// The top-level GPX data objects written out depend on the <see cref="IFeature.Geometry"/>
        /// type, as follows:
        /// <list type="table">
        /// <listheader>
        /// <term>Type of <see cref="IFeature.Geometry"/></term>
        /// <term>Corresponding top-level data object</term>
        /// </listheader>
        /// <item>
        /// <term><see cref="IPoint"/></term>
        /// <term><see cref="GpxWaypoint"/></term>
        /// </item>
        /// <item>
        /// <term><see cref="ILineString"/></term>
        /// <term><see cref="GpxRoute"/></term>
        /// </item>
        /// <item>
        /// <term><see cref="IMultiLineString"/></term>
        /// <term><see cref="GpxTrack"/></term>
        /// </item>
        /// </list>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// Thrown when <paramref name="writer"/>, <paramref name="metadata"/>, or
        /// <paramref name="features"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when an element of <paramref name="features"/> or its
        /// <see cref="IFeature.Geometry"/> is <see langword="null" />, or is not an instance of one
        /// of the recognized geometry types (see remarks).
        /// </exception>
        public static void Write(XmlWriter writer, GpxWriterSettings settings, GpxMetadata metadata, IEnumerable <IFeature> features, object extensions)
        {
            if (writer is null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            if (metadata is null)
            {
                throw new ArgumentNullException(nameof(metadata));
            }

            if (features is null)
            {
                throw new ArgumentNullException(nameof(features));
            }

            var waypoints = new List <GpxWaypoint>();
            var routes    = new List <GpxRoute>();
            var tracks    = new List <GpxTrack>();

            foreach (var feature in features)
            {
                switch (feature?.Geometry)
                {
                case null:
                    throw new ArgumentException("All features must be non-null and contain non-null geometries.", nameof(features));

                case IPoint _:
                    waypoints.Add(NetTopologySuiteGpxFeatureConverter.ToGpxWaypoint(feature));
                    break;

                case ILineString _:
                    routes.Add(NetTopologySuiteGpxFeatureConverter.ToGpxRoute(feature));
                    break;

                case IMultiLineString _:
                    tracks.Add(NetTopologySuiteGpxFeatureConverter.ToGpxTrack(feature));
                    break;

                default:
                    throw new ArgumentException("All features must be either IPoint (for wpt), ILineString (for rte), or IMultiLineString (for trk).  Not " + feature.Geometry.GetType(), nameof(features));
                }
            }

            Write(writer, settings, metadata, waypoints, routes, tracks, extensions);
        }
Beispiel #4
0
        /// <summary>
        /// Writes the given features to an <see cref="XmlWriter"/>.
        /// </summary>
        /// <param name="writer">
        /// The <see cref="XmlWriter"/> to write to.
        /// </param>
        /// <param name="settings">
        /// The <see cref="GpxWriterSettings"/> instance to use to control how GPX instances get
        /// written out, or <c>null</c> to use a general-purpose default.
        /// </param>
        /// <param name="metadata">
        /// The <see cref="GpxMetadata"/> instance that includes metadata about the file.  Required.
        /// </param>
        /// <param name="waypoints">
        /// The top-level wpt instances to write out.  Optional, but if specified, each element must
        /// be non-<see langword="null"/>.
        /// </param>
        /// <param name="routes">
        /// The top-level rte instances to write out.  Optional, but if specified, each element must
        /// be non-<see langword="null"/>.
        /// </param>
        /// <param name="tracks">
        /// The top-level trk instances to write out.  Optional, but if specified, each element must
        /// be non-<see langword="null"/>.
        /// </param>
        /// <param name="extensions">
        /// The top-level extension data.  Optional.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when <paramref name="writer"/> or <paramref name="metadata"/> is
        /// <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when an element of <paramref name="waypoints"/>, <paramref name="routes"/>, or
        /// <paramref name="tracks"/> is <see langword="null"/>.
        /// </exception>
        public static void Write(XmlWriter writer, GpxWriterSettings settings, GpxMetadata metadata, IEnumerable <GpxWaypoint> waypoints, IEnumerable <GpxRoute> routes, IEnumerable <GpxTrack> tracks, object extensions)
        {
            if (writer is null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            if (metadata is null)
            {
                throw new ArgumentNullException(nameof(metadata));
            }

            settings = settings ?? new GpxWriterSettings();

            writer.WriteStartDocument();
            writer.WriteGpxStartElement("gpx");
            writer.WriteAttributeString("version", "1.1");
            writer.WriteAttributeString("creator", metadata.Creator);
            if (!metadata.IsTrivial)
            {
                writer.WriteGpxStartElement("metadata");
                metadata.Save(writer, settings);
                writer.WriteEndElement();
            }

            Func <object, IEnumerable <XElement> > waypointExtensionCallback = settings.ExtensionWriter.ConvertWaypointExtension;

            foreach (var waypoint in waypoints ?? Enumerable.Empty <GpxWaypoint>())
            {
                if (waypoint is null)
                {
                    throw new ArgumentException("All waypoints must be non-null.", nameof(waypoints));
                }

                writer.WriteGpxStartElement("wpt");
                waypoint.Save(writer, settings, waypointExtensionCallback);
                writer.WriteEndElement();
            }

            foreach (var route in routes ?? Enumerable.Empty <GpxRoute>())
            {
                if (route is null)
                {
                    throw new ArgumentException("All routes must be non-null.", nameof(routes));
                }

                writer.WriteGpxStartElement("rte");
                route.Save(writer, settings);
                writer.WriteEndElement();
            }

            foreach (var track in tracks ?? Enumerable.Empty <GpxTrack>())
            {
                if (track is null)
                {
                    throw new ArgumentException("All tracks must be non-null.", nameof(tracks));
                }

                writer.WriteGpxStartElement("trk");
                track.Save(writer, settings);
                writer.WriteEndElement();
            }

            writer.WriteExtensions(extensions, settings.ExtensionWriter.ConvertGpxExtension);

            writer.WriteEndElement();
            writer.WriteEndDocument();
        }
Beispiel #5
0
        public void CustomRootNamespacesShouldBeAbleToBeSpecified()
        {
            const string DesiredPrefix = "ABC";
            const string NamespaceName = "http://www.example.com/xml";

            string expected = $@"
<gpx xmlns='http://www.topografix.com/GPX/1/1' version='1.1' creator='Creator' xmlns:{DesiredPrefix}= '{NamespaceName}'>
    <extensions>
        <{DesiredPrefix}:Key>Value</{DesiredPrefix}:Key>
    </extensions>
</gpx>";

            XElement parsedRoot;

            using (var ms = new MemoryStream())
            {
                var xmlWriterSettings = new XmlWriterSettings {
                    Encoding = Encoding.UTF8, CloseOutput = false, NamespaceHandling = NamespaceHandling.OmitDuplicates
                };
                using (var wr = XmlWriter.Create(ms, xmlWriterSettings))
                {
                    var gpxWriterSettings = new GpxWriterSettings
                    {
                        CommonXmlNamespacesByDesiredPrefix =
                        {
                            [DesiredPrefix] = new Uri(NamespaceName),
                        },
                    };

                    XElement[] extensions = { new XElement(XName.Get("Key", NamespaceName), "Value"), };

                    GpxWriter.Write(wr, gpxWriterSettings, new GpxMetadata("Creator"), Enumerable.Empty <IFeature>(), extensions);
                }

                ms.Position = 0;
                parsedRoot  = XDocument.Load(ms).Root;
            }

            // first check that it defines the same content
            var diff = DiffBuilder.Compare(expected)
                       .NormalizeWhitespace()
                       .WithTest(parsedRoot)
                       .IgnoreComments()
                       .CheckForSimilar()
                       .Build();

            Assert.False(diff.HasDifferences(), string.Join(Environment.NewLine, diff.Differences));

            // everything above actually passes without the fix for #36 or if we ignore the desired
            // prefix that we're given, so make sure to test that we actually put the namespace
            // declaration on the root with the desired prefix.
            Assert.Equal(DesiredPrefix, parsedRoot.GetPrefixOfNamespace(NamespaceName));

            // prove that, with NamespaceHandling.OmitDuplicates, duplicates are actually omitted.
            var redundantDeclarations = from descendant in parsedRoot.Descendants()
                                        from attribute in descendant.Attributes()
                                        where attribute.IsNamespaceDeclaration && attribute.Value == NamespaceName
                                        select(descendant, attribute);

            Assert.Empty(redundantDeclarations);
        }