2015-05-07 3 views
0

У меня есть XML-структуру (только сниппета) следующим образом:XMLReader: Получить значение дочернего узла, если другой дочерний узел содержит специальную строку

<ttOutput> 
    <ttOutputRow> 
     <cKey>key</cKey> 
     <cValue>value</cValue> 
    </ttOutputRow> 
    <ttOutputRow> 
     <cKey>findMe</cKey> 
     <cValue>value</cValue> 
    </ttOutputRow> 
    <ttOutputRow> 
     <cKey>key</cKey> 
     <cValue>value</cValue> 
    </ttOutputRow> 
</ttOutput> 

Для этого я хочу использовать XMLReader, чтобы сохранить память на низком уровне. Я ищу cValue if cKey is findMe. Как я могу получить это значение?

Это то, что я пробовал:

using (var stream = new StreamReader(path)) 
using (XmlReader reader = XmlReader.Create(stream)) 
{ 
    while(reader.Read()) 
    { 
     if (reader.IsStartElement()) 
     { 
      Console.WriteLine (reader.Name); 
      if (reader.Name == "ttOutputRow") { 
       XmlReader subreader = reader.ReadSubtree(); 
       while (subreader.Read()) { 
        if (subreader.Name == "cKey" && subreader.Value == "findMe") { 
         subreader.ReadToNextSibling ("cValue"); 
         Console.WriteLine ("found"); 
        } 
       } 
      } 
     } 
    } 
} 

Возможно, я могу использовать ReadToDescendant(String) или ReadSubtree() здесь, но я не знаю, как правильно его использовать.

Edit:

Это, кажется, еще один вариант использования ReadToDescendant:

while(reader.Read()) 
{ 
    reader.ReadToFollowing ("ttOutputRow"); 
    do { 
     if (reader.ReadToDescendant ("cKey")) { 
      if (reader.ReadInnerXml() == "findMe") { 
       reader.ReadToNextSibling ("cValue"); 
       Console.WriteLine ("found"); 
      } 
     } 
    } while (reader.ReadToFollowing ("ttOutputRow")); 
} 

Я также узнал, что вы можете использовать только ReadInnerXml() один раз.

+0

Я думаю, вы бы лучше использовать XPath, смотрите по адресу: https: //msdn.microsoft.com/en-us/library/ms256086%28v=vs.110%29.aspx –

+0

Я не хочу загружать весь файл в память, потому что он большой для моего приложения. – testing

ответ

1

Используйте subreader.Value, когда читатель указывает на ребенка текстового узла вместо указывая на родительского узла элемента. Вы можете также использовать ReadInnerXml(), чтобы получить текстовое значение узла элемента при условии, что элемент не имеет дочерний элемент, например:

if (subreader.Name == "cKey" && subreader.ReadInnerXml() == "findMe") 
{ 
    subreader.ReadToNextSibling("cValue"); 
    Console.WriteLine ("found: {0}", subreader.ReadInnerXml()); 
    //output: 
    //found: value 
} 
+0

Имеет ли использование * subreader * потребность в памяти, потому что одновременно работают два считывателя? Считаете ли вы, что чтение файла напрямую, а не использование «StreamReader», лучше (больше памяти)? Я обновил свой вопрос с помощью примера с помощью ReadToDescendant. Использует ли 'ReadToDescendant' или' ReadSubtree' лучше? Есть ли возможность стекать 'ReadInnerXml' в поток, чтобы в памяти не было всего? – testing

+0

Должен ли я проверить 'reader.NodeType == XmlNodeType.Element'? Или это не нужно? – testing

+1

Поскольку большинство методов XmlReader, используемых в вашем коде, получает имя элемента в качестве параметра -fe 'ReadToDescendant (« elementName ») - проверка на' NodeType' не нужна. Я думаю, что тип в этом случае должен быть «XmlNodeType». Element'. – har07

Смежные вопросы