Как читать / писать узлы и дочерние узлы из XML-файла в C #, возможно, с помощью xpath? - PullRequest
1 голос
/ 13 ноября 2009

Может быть, кто-нибудь может мне помочь. Мне нужно два метода.

Первый должен открыть файл 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. public static void 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 # гуру и другие люди, которые знают, как это сделать, ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, помогите мне! Я не знаю, как это сделать.

С уважением!

Ответы [ 3 ]

1 голос
/ 14 ноября 2009

Вы можете выполнять весь поиск, используя XPath.

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

В этом случае nodes будет содержать все элементы MenuItem, которые являются дочерними для элемента Menu верхнего уровня.

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

В этом случае nodes будет содержать все элементы MenuItem, являющиеся потомками либо Menu, либо MenuItem, являющиеся потомками Menu.

Вы также можете найти все MenuItem узлы, которые имеют не более 1 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;
}
0 голосов
/ 14 ноября 2009

Оба решения работают. Но когда до этого искомый узел выглядит примерно так:

<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>

тогда решения не работают. Как удалить только строку схемы или просто пропустить или что-то в этом роде

Может кто-нибудь из вас знает, почему и как решить эту проблему?

Привет!

0 голосов
/ 13 ноября 2009

EDIT:

Чтобы использовать 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 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...