diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/Program.cs b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/Program.cs index 9aa91deee0..39a30c440d 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/Program.cs +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/Program.cs @@ -1,13 +1,16 @@ using SelectingXmlNodesWithXpath; using System.Xml; +using System.Xml.Linq; + +var path = Path.Combine(AppContext.BaseDirectory, "BooksCatalog.xml"); var doc = new XmlDocument(); -doc.Load("BooksCatalog.xml"); +doc.Load(path); var root = doc.DocumentElement!; Console.WriteLine("Selected book:"); var singleResult = XmlNodesSelector.SelectSingleBook(root); -Console.WriteLine(singleResult); +Console.WriteLine(singleResult ?? "No book matched the query."); Console.WriteLine("\nSelected books:"); var results = XmlNodesSelector.SelectBooks(root); @@ -15,4 +18,8 @@ Console.WriteLine("\nSelected books:"); var resultsFromNamespaces = XmlNodesSelector.SelectBooksUsingNamespaces(doc); -resultsFromNamespaces.ForEach(Console.WriteLine); \ No newline at end of file +resultsFromNamespaces.ForEach(Console.WriteLine); + +Console.WriteLine("\nSelected books with LINQ to XML:"); +var linqResults = XmlNodesSelector.SelectBooksWithLinqToXml(XDocument.Load(path)); +linqResults.ForEach(Console.WriteLine); diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath.csproj b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath.csproj index 13e09a4050..b894a2e9cc 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath.csproj +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/XmlNodesSelector.cs b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/XmlNodesSelector.cs index 0dcd38eb02..ef7d7e2009 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/XmlNodesSelector.cs +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpath/XmlNodesSelector.cs @@ -1,5 +1,6 @@ using System.Xml; using System.Xml.Linq; +using System.Xml.XPath; namespace SelectingXmlNodesWithXpath; @@ -10,18 +11,23 @@ public static string FormatXml(string unformattedXml) return XElement.Parse(unformattedXml).ToString(); } - public static string SelectSingleBook(XmlNode root) + public static string? SelectSingleBook(XmlNode root) { var node = root.SelectSingleNode("//catalog/book[position()=2]"); - - return FormatXml(node!.OuterXml); + + return node is null ? null : FormatXml(node.OuterXml); } public static List SelectBooks(XmlNode root) { var nodes = root.SelectNodes("//catalog/book[price<50.00]"); - return nodes! + if (nodes is null) + { + return []; + } + + return nodes .Cast() .Select(x => FormatXml(x.OuterXml)) .ToList(); @@ -34,9 +40,22 @@ public static List SelectBooksUsingNamespaces(XmlDocument doc) var nodes = doc.SelectNodes("descendant::ex:book", nsmgr); - return nodes! + if (nodes is null) + { + return []; + } + + return nodes .Cast() .Select(x => FormatXml(x.OuterXml)) .ToList(); } + + public static List SelectBooksWithLinqToXml(XDocument doc) + { + return doc + .XPathSelectElements("//catalog/book[price<50.00]") + .Select(x => x.ToString()) + .ToList(); + } } diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/GlobalUsings.cs b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/GlobalUsings.cs index 47c68f284e..6f54963f00 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/GlobalUsings.cs +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/GlobalUsings.cs @@ -1,3 +1,4 @@ global using SelectingXmlNodesWithXpath; global using System.Xml; -global using Xunit; \ No newline at end of file +global using Xunit; +global using System.Xml.Linq; diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/Tests.csproj b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/Tests.csproj index 4d8871fd89..aa17d0c4ed 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/Tests.csproj +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net10.0 enable enable @@ -16,13 +16,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/XmlNodesSelectorTest.cs b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/XmlNodesSelectorTest.cs index ae42800b5b..7334e77458 100644 --- a/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/XmlNodesSelectorTest.cs +++ b/xml-csharp/SelectingXmlNodesWithXpath/SelectingXmlNodesWithXpathTests/XmlNodesSelectorTest.cs @@ -64,7 +64,7 @@ public void GivenAnXmlFile_WhenSelectingASingleNode_ThenReturnsTheSecondPosition { var result = XmlNodesSelector.SelectSingleBook(_document.DocumentElement!); - Assert.Equal(result, _expectedResults["Book2"]); + Assert.Equal(result?.ReplaceLineEndings(), _expectedResults["Book2"].ReplaceLineEndings()); } [Fact] @@ -72,10 +72,12 @@ public void GivenAnXmlFile_WhenSelectingNodes_ThenReturnBooksWithPriceLowerThan5 { var expected = _expectedResults .Where(pair => pair.Key is "Book1" or "Book3") - .Select(pair => pair.Value) + .Select(pair => pair.Value.ReplaceLineEndings()) .ToList(); - var result = XmlNodesSelector.SelectBooks(_document.DocumentElement!); + var result = XmlNodesSelector.SelectBooks(_document.DocumentElement!) + .Select(x => x.ReplaceLineEndings()) + .ToList(); Assert.Equal(result, expected); } @@ -86,11 +88,53 @@ public void GivenAnXmlFile_WhenSelectingNodesUsingNamespaces_ThenReturnBookEleme var expected = _expectedResults .Where(pair => pair.Key is "Book4") - .Select(pair => pair.Value) + .Select(pair => pair.Value.ReplaceLineEndings()) .ToList(); - var result = XmlNodesSelector.SelectBooksUsingNamespaces(_document); + var result = XmlNodesSelector.SelectBooksUsingNamespaces(_document) + .Select(x => x.ReplaceLineEndings()) + .ToList(); Assert.Equal(result, expected); } -} \ No newline at end of file + + [Fact] + public void GivenAnXmlFile_WhenSelectSingleNodeMatchesNothing_ThenReturnsNull() + { + var node = _document.DocumentElement!.SelectSingleNode("//catalog/book[price>1000]"); + + Assert.Null(node); + } + + [Fact] + public void GivenAnXmlFile_WhenSelectNodesMatchesNothing_ThenReturnsAnEmptyList() + { + var nodes = _document.DocumentElement!.SelectNodes("//catalog/book[price>1000]"); + + Assert.NotNull(nodes); + Assert.Equal(0, nodes.Count); + } + + [Fact] + public void GivenABookInADefaultNamespace_WhenQueryingWithAnUnprefixedName_ThenReturnsThreeOfTheFourBooks() + { + var nodes = _document.DocumentElement!.SelectNodes("//catalog/book"); + + Assert.NotNull(nodes); + Assert.Equal(3, nodes.Count); + } + + [Fact] + public void GivenAnXDocument_WhenSelectingWithXPathSelectElements_ThenReturnsTheSameBooksAsSelectNodes() + { + var expected = XmlNodesSelector.SelectBooks(_document.DocumentElement!) + .Select(x => x.ReplaceLineEndings()) + .ToList(); + + var result = XmlNodesSelector.SelectBooksWithLinqToXml(XDocument.Load("BooksCatalog.xml")) + .Select(x => x.ReplaceLineEndings()) + .ToList(); + + Assert.Equal(expected, result); + } +}