Skip to content

Commit 7db8969

Browse files
CM-793: Selecting Xml Nodes With Xpath in C# (#1392)
* Adding new project * CM-793: Initial commit * CM-793: Fixing line endings inconsistencies * CM-793: Converting to file scoped namespace * CM-793: Removing try-catch clause * CM-793: Externalizing methods to a new class * CM-793: Moving to top level statement * CM-793: Removing usings * CM-793: Using Scoped level statements * CM-793: Removing extra blank line, try-catch clause and comments * CM-793: Expliciting fields as private and renaming variables * CM-793: Converting string to raw string literal * CM-793: Fixing warnings * CM-793: Creating resources folder and sharing file between projects as a link * CM-793: Renaming to var and replacing tabs * CM-793: Rename the class to match implementation class' name. * CM-793: Formatting the raw string. New function to format outter xml for comparison * CM-793: Changing the methods to return strings and the unit tests to validate each method * CM-793: Removing unused usings, moving usings to the GlobalUsings file, inserting is and or keywords * CM-793: returning result directly * CM-793: Properties with get only * Update XmlNodesSelector.cs * CM-793: Converting properties to private fields. --------- Co-authored-by: André Carvalho <[email protected]>
1 parent a8ceb66 commit 7db8969

File tree

8 files changed

+273
-0
lines changed

8 files changed

+273
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<catalog>
3+
<book id="1">
4+
<author>King, Stephen</author>
5+
<title>IT</title>
6+
<genre>Horror</genre>
7+
<price>40.00</price>
8+
</book>
9+
<book id="2">
10+
<author>Assis, Machado De</author>
11+
<title>Dom Casmurro</title>
12+
<genre>Romance</genre>
13+
<price>50.00</price>
14+
</book>
15+
<book id="3">
16+
<author>Calaprice, Alice; Lipscombe, Trevor</author>
17+
<title>Albert Einstein: A Biography</title>
18+
<genre>Biography</genre>
19+
<price>30.00</price>
20+
</book>
21+
<book id="4" xmlns="urn:example-schema">
22+
<author>Fowler, Martin; Beck, Kent</author>
23+
<title>Refactoring: Improving the design of existing code</title>
24+
<genre>Scientific</genre>
25+
<price>60.00</price>
26+
</book>
27+
</catalog>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.7.34009.444
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelectingXmlNodesWithXpath", "SelectingXmlNodesWithXpath\SelectingXmlNodesWithXpath.csproj", "{24D1C369-9F69-4A7D-9F69-CFE64A250782}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "SelectingXmlNodesWithXpathTests\Tests.csproj", "{D259B75F-5A4D-4F5D-B5CD-70FF423AAF41}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resources", "Resources", "{EF669DD0-CD35-449D-8843-521ED946F592}"
11+
ProjectSection(SolutionItems) = preProject
12+
Resources\BooksCatalog.xml = Resources\BooksCatalog.xml
13+
EndProjectSection
14+
EndProject
15+
Global
16+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17+
Debug|Any CPU = Debug|Any CPU
18+
Release|Any CPU = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
21+
{24D1C369-9F69-4A7D-9F69-CFE64A250782}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{24D1C369-9F69-4A7D-9F69-CFE64A250782}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
{24D1C369-9F69-4A7D-9F69-CFE64A250782}.Release|Any CPU.ActiveCfg = Release|Any CPU
24+
{24D1C369-9F69-4A7D-9F69-CFE64A250782}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{D259B75F-5A4D-4F5D-B5CD-70FF423AAF41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{D259B75F-5A4D-4F5D-B5CD-70FF423AAF41}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{D259B75F-5A4D-4F5D-B5CD-70FF423AAF41}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{D259B75F-5A4D-4F5D-B5CD-70FF423AAF41}.Release|Any CPU.Build.0 = Release|Any CPU
29+
EndGlobalSection
30+
GlobalSection(SolutionProperties) = preSolution
31+
HideSolutionNode = FALSE
32+
EndGlobalSection
33+
GlobalSection(ExtensibilityGlobals) = postSolution
34+
SolutionGuid = {461A3B4E-0B19-457D-96E6-E4A35EB6134C}
35+
EndGlobalSection
36+
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using SelectingXmlNodesWithXpath;
2+
using System.Xml;
3+
4+
var doc = new XmlDocument();
5+
doc.Load("BooksCatalog.xml");
6+
var root = doc.DocumentElement!;
7+
8+
Console.WriteLine("Selected book:");
9+
var singleResult = XmlNodesSelector.SelectSingleBook(root);
10+
Console.WriteLine(singleResult);
11+
12+
Console.WriteLine("\nSelected books:");
13+
var results = XmlNodesSelector.SelectBooks(root);
14+
results.ForEach(Console.WriteLine);
15+
16+
Console.WriteLine("\nSelected books:");
17+
var resultsFromNamespaces = XmlNodesSelector.SelectBooksUsingNamespaces(doc);
18+
resultsFromNamespaces.ForEach(Console.WriteLine);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net7.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<Content Include="..\Resources\BooksCatalog.xml" Link="BooksCatalog.xml">
12+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
13+
</Content>
14+
</ItemGroup>
15+
16+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Xml;
2+
using System.Xml.Linq;
3+
4+
namespace SelectingXmlNodesWithXpath;
5+
6+
public static class XmlNodesSelector
7+
{
8+
public static string FormatXml(string unformattedXml)
9+
{
10+
return XElement.Parse(unformattedXml).ToString();
11+
}
12+
13+
public static string SelectSingleBook(XmlNode root)
14+
{
15+
var node = root.SelectSingleNode("//catalog/book[position()=2]");
16+
17+
return FormatXml(node!.OuterXml);
18+
}
19+
20+
public static List<string> SelectBooks(XmlNode root)
21+
{
22+
var nodes = root.SelectNodes("//catalog/book[price<50.00]");
23+
24+
return nodes!
25+
.Cast<XmlNode>()
26+
.Select(x => FormatXml(x.OuterXml))
27+
.ToList();
28+
}
29+
30+
public static List<string> SelectBooksUsingNamespaces(XmlDocument doc)
31+
{
32+
var nsmgr = new XmlNamespaceManager(doc.NameTable);
33+
nsmgr.AddNamespace("ex", "urn:example-schema");
34+
35+
var nodes = doc.SelectNodes("descendant::ex:book", nsmgr);
36+
37+
return nodes!
38+
.Cast<XmlNode>()
39+
.Select(x => FormatXml(x.OuterXml))
40+
.ToList();
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
global using SelectingXmlNodesWithXpath;
2+
global using System.Xml;
3+
global using Xunit;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<Content Include="..\Resources\BooksCatalog.xml" Link="BooksCatalog.xml">
14+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
15+
</Content>
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
20+
<PackageReference Include="xunit" Version="2.4.2" />
21+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
22+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
23+
<PrivateAssets>all</PrivateAssets>
24+
</PackageReference>
25+
<PackageReference Include="coverlet.collector" Version="3.2.0">
26+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
27+
<PrivateAssets>all</PrivateAssets>
28+
</PackageReference>
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<ProjectReference Include="..\SelectingXmlNodesWithXpath\SelectingXmlNodesWithXpath.csproj" />
33+
</ItemGroup>
34+
35+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
namespace SelectingXmlNodesWithXpathTests;
2+
3+
public class XmlNodesSelectorTest
4+
{
5+
private readonly XmlDocument _document;
6+
private readonly Dictionary<string, string> _expectedResults;
7+
8+
public XmlNodesSelectorTest()
9+
{
10+
_document = new XmlDocument();
11+
_document.Load("BooksCatalog.xml");
12+
13+
_expectedResults = new Dictionary<string, string>()
14+
{
15+
{
16+
"Book1",
17+
"""
18+
<book id="1">
19+
<author>King, Stephen</author>
20+
<title>IT</title>
21+
<genre>Horror</genre>
22+
<price>40.00</price>
23+
</book>
24+
"""
25+
},
26+
{
27+
"Book2",
28+
"""
29+
<book id="2">
30+
<author>Assis, Machado De</author>
31+
<title>Dom Casmurro</title>
32+
<genre>Romance</genre>
33+
<price>50.00</price>
34+
</book>
35+
"""
36+
},
37+
{
38+
"Book3",
39+
"""
40+
<book id="3">
41+
<author>Calaprice, Alice; Lipscombe, Trevor</author>
42+
<title>Albert Einstein: A Biography</title>
43+
<genre>Biography</genre>
44+
<price>30.00</price>
45+
</book>
46+
"""
47+
},
48+
{
49+
"Book4",
50+
"""
51+
<book id="4" xmlns="urn:example-schema">
52+
<author>Fowler, Martin; Beck, Kent</author>
53+
<title>Refactoring: Improving the design of existing code</title>
54+
<genre>Scientific</genre>
55+
<price>60.00</price>
56+
</book>
57+
"""
58+
}
59+
};
60+
}
61+
62+
[Fact]
63+
public void GivenAnXmlFile_WhenSelectingASingleNode_ThenReturnsTheSecondPosition()
64+
{
65+
var result = XmlNodesSelector.SelectSingleBook(_document.DocumentElement!);
66+
67+
Assert.Equal(result, _expectedResults["Book2"]);
68+
}
69+
70+
[Fact]
71+
public void GivenAnXmlFile_WhenSelectingNodes_ThenReturnBooksWithPriceLowerThan50()
72+
{
73+
var expected = _expectedResults
74+
.Where(pair => pair.Key is "Book1" or "Book3")
75+
.Select(pair => pair.Value)
76+
.ToList();
77+
78+
var result = XmlNodesSelector.SelectBooks(_document.DocumentElement!);
79+
80+
Assert.Equal(result, expected);
81+
}
82+
83+
[Fact]
84+
public void GivenAnXmlFile_WhenSelectingNodesUsingNamespaces_ThenReturnBookElementWithNamespace()
85+
{
86+
var expected =
87+
_expectedResults
88+
.Where(pair => pair.Key is "Book4")
89+
.Select(pair => pair.Value)
90+
.ToList();
91+
92+
var result = XmlNodesSelector.SelectBooksUsingNamespaces(_document);
93+
94+
Assert.Equal(result, expected);
95+
}
96+
}

0 commit comments

Comments
 (0)