繁体   English   中英

如何使用xpath从C#中的xml文件读取/写入节点和子节点?

[英]How to read/write nodes and child nodes from xml file in c# maybe using xpath?

也许有人可以帮助我。 我需要两种方法。

第一个应该打开一个xml文件,并获取具有给定参数的所有节点,即:

XML文件(file.xml):

<Menu id="1" Name="myMenu">
  <MenuItem Header="Header 1" Name="header1" />
  <MenuItem Header="Header 2" Name="header2">
    <MenuItem Header="subHeader 2.1" Name="header2_1">
      <MenuItem Header="subsubHeader 2.1.1" Name="header2_1_1" />
    </MenuItem>
  </MenuItem>
  <MenuItem Header="Header 3" Name="header3" />
</Menu>

因此,现在我需要使用以下方法从xml中获取值:

public static List<string, string>ReadXML(string filename, string node, string[] attributes, bool searchSubNodes);

调用方法示例: ReadXMLValues("file.xml", "MenuItem", new string[] {"Header", "Name"}, true);

这将返回两个字符串的列表,例如:

"Header 1", "header1"
"Header 2", "header2"
"subHeader 2.1", "header2_1" <-- this should be in the list only if searchSubNodes is enabled!
"subsubHeader 2.1.1", "header2_1_1" <-- the same for this one!!!
"Header 3", "header3"

这是阅读部分,现在是写作部分:

文件名与上面的file.xml相同。 公共静态无效WriteXML(字符串文件名,字符串节点,列表属性);

现在让我们说file.xml具有空的标题属性,如下所示:

<Menu id="1" Name="myMenu">
  <MenuItem Header="" Name="header1" />
  <MenuItem Header="" Name="header2">

我需要将值放入标头中,最终结果应如下所示:

   <Menu id="1" Name="myMenu">
      <MenuItem Header="Header 1" Name="header1" />
      <MenuItem Header="Header 2" Name="header2">

这样的事情可能吗??? C#专家和其他知道如何执行此操作的人请帮助我! 我不知道该怎么做。

最好的祝福!

您可以使用XPath进行所有搜索。

XmlNodeList nodes = doc.SelectNodes("/Menu/MenuItem");

在这种情况下, nodes将包含作为顶级Menu元素的子元素的所有MenuItem元素。

XmlNodeList nodes = doc.SelectNodes("/Menu/MenuItem | /Menu/MenuItem/MenuItem");

在这种情况下, nodes将包含所有MenuItem是儿童或者元素Menu或的MenuItem这是一个儿童Menu

您还可以找到所有不超过1个MenuItem祖先的MenuItem节点:

XmlNodeList nodes = doc.SelectNodes("//MenuItem[count(ancestor::MenuItem) &lt; 2]");

或者,您可以找到所有MenuItem节点:

XmlNodeList nodes = doc.SelectNodes("//MenuItem");

无论您选择选择它们,处理元素的方式都相同:

foreach (XmlElement elm in nodes)
{
   myList.Add(new[] { elm.GetAttribute("Header"), elm.GetAttribute("Name") });
}

因此,这建议您可以使用建议的签名将其封装为方法:

public static List<IEnumerable<string>>ReadXML(
   string filename, 
   string elementName, 
   IEnumerable<string> attributes, 
   bool searchSubNodes)
{
   XmlDocument d = new XmlDocument();
   d.Load(filename);
   string xpath = searchSubNodes ? "//" + elementName : "/*/elementName";
   List<IEnumerable<string>> results = new List<IEnumerable<string>>();
   foreach (XmlElement elm in d.SelectNodes(xpath))
   {
      var values = from name in attributes select elm.GetAttribute(name);
      result.Add(values.ToArray());
   }
   return result;
}

编辑:

要使用XPath选择具有给定节点名和两个给定属性的所有节点,请使用以下XPath表达式(我不知道是否有更好的方法可以做到这一点,但这是可行的):

//NodeName[@FirstAttributeName][@SecondAttributeName]

在代码中,您可以这样做(对于示例中的MenuItems)。 我更新了代码,使放置在文档中的名称空间在前缀“ x”下成为已知。 此外,XPath表达式已更新为在节点之前使用该前缀。

XPathDocument doc = new XPathDocument("data2.xml");
XPathNavigator nav = doc.CreateNavigator();
XmlNamespaceManager mgr = new XmlNamespaceManager(nav.NameTable);
mgr.AddNamespace("default", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
XPathNodeIterator iterator = nav.Select("//default:MenuItem[@Header][@Name]", mgr);

while (iterator.MoveNext())
{
    Console.Write(iterator.Current.GetAttribute("Header", ""));
    Console.Write(iterator.Current.GetAttribute("Name", ""));
    Console.Write(Environment.NewLine);
}

=====

您必须使用XPath吗? 您可以只为Menu / MenuItem创建映射到XML的类,如下所示:

public class Menu
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<MenuItem> SubItems { get; set; }
}

public class MenuItem
{
    public string Header { get; set; }
    public string Name { get; set; }
    public List<MenuItem> SubItems { get; set; }
}

然后让XMLSerializer为您完成工作(它可以同时进行读取和编写)。 之后,您可以将过滤应用于内存列表(例如,使用Linq-To-Objects)。

如果您想使用XPath做到这一点,这篇Codeproject文章可能会有所帮助。

两种解决方案均有效。 但是在搜索到的节点之前是这样的:

<MenuItem x:Class="Test.Win"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/Test" <--this line make problems!
Header="Main" Name="Main">
<Menu id="1" Name="myMenu">
  <MenuItem Header="Header 1" Name="header1" />
  <MenuItem Header="Header 2" Name="header2">
    <MenuItem Header="subHeader 2.1" Name="header2_1">
      <MenuItem Header="subsubHeader 2.1.1" Name="header2_1_1" />
    </MenuItem>
  </MenuItem>
  <MenuItem Header="Header 3" Name="header3" />
</Menu>

</MyNode>

那么解决方案就行不通了。 如何仅删除架构行或仅跳过它或类似内容

你们中的某人是否知道为什么以及如何解决此问题?

问候!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM