XPath匹配XML序列化DataContract类

时间:2014-04-11 15:27:53

标签: c# xml serialization xpath match

我有一个DataContractMyDataContract。我将它序列化为XML文件。后来,在一个完全不同的地方"在我的应用程序中,我正在加载此文件。如果文件的内容符合特殊条件,我想验证仅加载。假设我将一个人和协会存储在该人的车辆上,假设一个人只能拥有一辆车。 : - )

这里是DataContract类:

namespace Test.DataContracts
{
  [DataContract]
  public class MyDataContract
  {
    [DataMember]
    public string Identifier { get; set; }

    [DataMember]
    public Common.Person Person { get; set; }

    [DataMember]
    public Common.Vehicle Vehicle { get; set; }
  }
}

namespace Test.DataContracts.Common
{
  [DataContract]
  public class Person
  {
    [DataMember]
    public Global.Gender Gender { get; set; }

    [DataMember]
    public string Info { get; set; }

    [DataMember]
    public string Name { get; set; }
  }

  [DataContract]
  public class Vehicle
  {
    [DataMember]
    public string Info { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string Vendor { get; set; }
  }
}

namespace Test.DataContracts.Global
{
  [DataContract]
  public class Gender
  {
    [DataMember]
    public int Type { get; set; }

    [DataMember]
    public string Name { get; set; }
  }
}

以下序列化XML中的结果:

<?xml version="1.0" encoding="utf-8"?>
<MyDataContract xmlns="http://schemas.datacontract.org/2004/07/Test.DataContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Identifier>123456789</Identifier>
  <Person xmlns:a="http://schemas.datacontract.org/2004/07/Test.DataContracts.Common">
    <a:Gender xmlns:b="http://schemas.datacontract.org/2004/07/Test.DataContracts.Global">
      <b:Name>Female</b:Name>
      <b:Type>0</b:Type>
    </a:Gender>
    <a:Info>She is a beautiful lady.</a:Info>
    <a:Name>Jane Doe</a:Name>
  </Person>
  <Vehicle xmlns:a="http://schemas.datacontract.org/2004/07/Test.DataContracts.Common">
    <a:Info>A super great car.</a:Info>
    <a:Name>Mustang 1983 Turbo GT</a:Name>
    <a:Vendor>Ford</a:Vendor>
  </Vehicle>
</MyDataContract>

现在我想过滤掉拥有任何福特(Type = 0)车辆的女(Vendor = Ford)人。我尝试了以下操作,但它总是会导致false匹配。

string path = @"c:\janedoe.xml";

var xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlNodeList xNodes = xmlDoc.SelectNodes(@"//namespace::*[not(. = ../../namespace::*)]");
var xNamespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);

foreach (XmlNode node in xNodes)
{
  if (!string.IsNullOrWhiteSpace(xNamespaceManager.LookupNamespace(node.LocalName))) continue;
  xNamespaceManager.AddNamespace(node.LocalName, node.Value);
}

using (var fs = new FileStream(path, FileMode.Open))
{
  var xDocument = new XPathDocument(fs);
  var xNavigator = xDocument.CreateNavigator();
  XPathExpression exp1 = xNavigator.Compile(string.Format("MyDataContract/Person/Gender/Type/descendant::*[contains(text(), '{0}')]", "0"));
  exp1.SetContext(xNamespaceManager);
  XPathExpression exp2 = xNavigator.Compile(string.Format("MyDataContract/Vehicle/Vendor/descendant::*[contains(text(), '{0}')]", "Ford"));
  exp2.SetContext(xNamespaceManager);

  if (xNavigator.Matches(exp1) && xNavigator.Matches(exp2))
  {
    Console.WriteLine("File '{0}' indicates a female person that owns a vehicle of Ford.", path);
  }
  else
  {
    Console.WriteLine("File '{0}' has no matches (female and Ford).", path);
  }
}

有人可以帮忙吗?

UPDATE 1 - 我已使用XmlNamespaceManager更改了代码。但在执行false时仍会导致xNavigator.Matches(exp1)

1 个答案:

答案 0 :(得分:1)

如果您有XDocument,则更容易使用LINQ-to-XML:

var xdoc = XDocument.Load(memorystream);
// Making it simple, grab the first
var type = xdoc.Descendants(XName.Get("Type","http://schemas.datacontract.org/2004/07/Test.DataContracts.Global")).FirstOrDefault();
var vendor = xdoc.Descendants(XName.Get("Vendor", "http://schemas.datacontract.org/2004/07/Test.DataContracts.Common")).FirstOrDefault();
string path = "blah";
if (type != null && type.Value == "0" && vendor != null && vendor.Value == "Ford")
{
    Console.WriteLine("File '{0}' indicates a female person that owns a vehicle of Ford.", path);
}
else
{
    Console.WriteLine("File '{0}' has no matches (female and Ford).", path);
}

如果您确定XPath是您需要的唯一解决方案:

using System.Xml.XPath;

var document = XDocument.Load(fileName);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("a", "http://schemas.datacontract.org/2004/07/Test.DataContracts.Global");
var name = document.XPathSelectElement("path", namespaceManager).Value;