CSharp · Console
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Net;
using System.Xml.XPath;
using System.Globalization;
using System.Collections;
// https://stackoverflow.com/questions/46774190/get-last-child-element-using-xmlreader
public static class XmlReaderExtensions
{
public static IEnumerable<IEnumerable<XElement>> ReadNestedElements(this XmlReader xmlReader, string outerName, string innerName)
{
while (!xmlReader.EOF)
{
if (xmlReader.NodeType == System.Xml.XmlNodeType.Element && xmlReader.Name == outerName)
{
using (var subReader = xmlReader.ReadSubtree())
{
yield return subReader.ReadElements(innerName);
}
}
xmlReader.Read();
}
}
public static IEnumerable<XElement> ReadElements(this XmlReader xmlReader, string name)
{
while (!xmlReader.EOF)
{
if (xmlReader.NodeType == System.Xml.XmlNodeType.Element && xmlReader.Name == name)
{
var element = (XElement)XNode.ReadFrom(xmlReader);
yield return element;
}
else
{
xmlReader.Read();
}
}
}
}
class TestClass
{
public static void Test()
{
Test(GetXml());
Console.WriteLine("\nAll tests passed.");
}
public static void Test(string xmlString)
{
Console.WriteLine("\nTesting XML: ");
Console.WriteLine(xmlString);
Console.WriteLine();
var indentedXml = XElement.Parse(xmlString).ToString(SaveOptions.None);
var unindentedXml = XElement.Parse(xmlString).ToString(SaveOptions.None);
var indentedValues = LastFieldValues(indentedXml);
var unindentedValues = LastFieldValues(unindentedXml);
Console.WriteLine("Indented last field values: ");
Console.WriteLine(String.Join(",", indentedValues));
Console.WriteLine("Unindented last field values: ");
Console.WriteLine(String.Join(",", unindentedValues));
// Parse the XML into an XDocument.
// You can use use XDocument.Load(fileName) to load from a file
var doc = XDocument.Parse(xmlString);
var xpathLastValues = doc
.XPathSelectElements(@"//fields/field/value[last()]")
.Select(e => e.Value)
.ToList();
Console.WriteLine("Last field values from XPathSelectElements(): ");
Console.WriteLine(String.Join(",", xpathLastValues));
Assert.IsTrue(indentedValues.SequenceEqual(unindentedValues));
Assert.IsTrue(xpathLastValues.SequenceEqual(unindentedValues));
}
static List<string> LastFieldValues(string xml)
{
using (var textReader = new StringReader(xml))
using (var xmlReader = XmlReader.Create(textReader))
{
return LastFieldValues(xmlReader);
}
}
public static List<string> LastFieldValues(XmlReader reader)
{
var query = reader.ReadNestedElements("field", "value")
.Select(l => l.LastOrDefault())
.Where(v => v != null)
.Select(v => (string)v);
return query.ToList();
}
static string GetXml()
{
var xml = @"<fields>
<field fieldid=""fdtElem3Group"">
<value actionid=""1"" actiontype=""review"">123456789</value>
<value actionid=""2"" actiontype=""review"">123456789</value>
<value actionid=""3"" actiontype=""review"">123456789</value>
<value actionid=""4"" actiontype=""review"">123456789</value>
<value actionid=""5"" actiontype=""review"">123456789</value>
</field>
<field fieldid=""fdtElem7Group"">
<value actionid=""1"" actiontype=""review"">29/10/75</value>
<value actionid=""2"" actiontype=""review"">29/10/74</value>
<value actionid=""3"" actiontype=""review"">29/10/74</value>
<value actionid=""4"" actiontype=""review"">29/10/76</value>
<value actionid=""5"" actiontype=""review"">29/10/74</value>
</field>
<field fieldid=""fdtElemNullGroup"" />
</fields>";
return xml;
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine();
TestClass.Test();
}
}