2015-07-17 3 views
0

Я использую XMLReader в C# для получения данных из XML-документа, полученного как часть веб-запроса. XML создается на основе параметров запроса, переданных службе, и может включать в себя множество элементов. Пример в этом вопросе основан на запросе инвентаризации.XMLReader.ReadToNextSibling перескакивает до конца файла

Вот урезанная версия XML:

<?xml version="1.0" encoding="utf-8"?> 
<ArrayOfQMXINVQ_INVENTORYType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<QMXINVQ_INVENTORYType> 
    <ABCTYPE>C</ABCTYPE> 
    <BINNUM>A-5-2</BINNUM> 
    <FREQUNIT /> 
    <GLACCOUNT> 
     <VALUE>????-???-200</VALUE> 
     <GLCOMP 
      glorder="2">200</GLCOMP> 
    </GLACCOUNT> 
    <INVENTORYID>140</INVENTORYID> 
    <INVGENTYPE /> 
    <ISSUEUNIT>EACH</ISSUEUNIT> 
    <VENDOR>ATI</VENDOR> 
    <INVBALANCES> 
     <BINNUM>A-5-2</BINNUM> 
        <CURBAL>6</CURBAL> 
     <STAGEDCURBAL>0</STAGEDCURBAL> 
     <STAGINGBIN>false</STAGINGBIN> 
    </INVBALANCES> 
    <ITEM> 
     <DESCRIPTION>Connecting Link - Repair</DESCRIPTION> 
     <EXTERNALREFID /> 
     <GROUPNAME /> 
     <ISSUEUNIT /> 
     <ITEMID>175</ITEMID> 
     <ITEMTYPE>ITEM</ITEMTYPE> 
     <LOTTYPE 
      maxvalue="NOLOT">NOLOT</LOTTYPE> 
    </ITEM> 
</QMXINVQ_INVENTORYType> 
<QMXINVQ_INVENTORYType> 
    <ABCTYPE>C</ABCTYPE> 
    <BINNUM>B-8-1</BINNUM> 
    <FREQUNIT /> 
    <GLACCOUNT> 
     <VALUE>????-???-300</VALUE> 
     <GLCOMP 
      glorder="2">300</GLCOMP> 
    </GLACCOUNT> 
    <INVENTORYID>142</INVENTORYID> 
    <INVGENTYPE /> 
    <ISSUEUNIT>EACH</ISSUEUNIT> 
    <VENDOR>ATI</VENDOR> 
    <INVBALANCES> 
     <BINNUM>B-8-1</BINNUM> 
        <CURBAL>5</CURBAL> 
     <STAGEDCURBAL>0</STAGEDCURBAL> 
     <STAGINGBIN>false</STAGINGBIN> 
    </INVBALANCES> 
    <ITEM> 
     <DESCRIPTION>Fence Stretcher</DESCRIPTION> 
     <EXTERNALREFID /> 
     <GROUPNAME /> 
     <ISSUEUNIT /> 
     <ITEMID>105</ITEMID> 
     <ITEMTYPE>ITEM</ITEMTYPE> 
     <LOTTYPE 
      maxvalue="NOLOT">NOLOT</LOTTYPE> 
    </ITEM> 
    </QMXINVQ_INVENTORYType> 

Вот код блока в вопросе:

 XmlTextReader reader = new XmlTextReader(strRespFile); 
    reader.MoveToContent(); 
    string topLevelElementName = reader.Name; 
    // We need to advance "i" rows here. 
    for (int k = 0; k < i; k++) 
    { 
     reader.ReadToNextSibling(topLevelElementName); 
    } 

    // Now, read the element's value for the column 
    while (reader.Read()) 
    { 
     if (reader.NodeType == XmlNodeType.Element) 
     { 
      if (reader.Name == c) 
      { 
       reader.Read(); 
       dr[c] = reader.Value; 
       break; 
      } 
     } 
    } 
    reader.Close(); 

код верхнего уровня (не показан), считывает дочерние элементы для данных. Если встречается дочерний элемент, выполняется код. Подчиненные первого дочернего элемента найдены и успешно добавлены в datatable.

<INVBALANCES> 
    <CURBAL>6</CURBAL> 
... 
<ITEM> 
    <DESCRIPTION>Connecting Link - Repair</DESCRIPTION> 

Последующие исполнения приводят к тому, что читатель прыгает прямо в конец файла. Любые идеи о том, почему он собирается EOF вместо чтения следующего ребенка?

ответ

1

Вы позиционируете читатель на root element"ArrayOfQMXINVQ_INVENTORYType", затем пытаясь прочитать его следующий родственный. Но корневой элемент не может иметь родного брата, потому что может быть только один. То, что вы хотите сделать, это:

  • Переход к корневому элементу
  • Почитай своего первого ребенка.
  • Перейти к дочернему элементу Kth корня с именем topLevelElementName.
  • Поиск его дочерних элементов.

Например:

 var xml = GetXml(); // Your sample XML as a string 

     int topLevelElementIndex = 1; 
     var topLevelElementName = "QMXINVQ_INVENTORYType"; 

     try 
     { 
      using (var sr = new StringReader(xml)) // You would use e.g. var sr = new StreamReader(strRespFile, Encoding.Encoding.UTF8) 
      using (var reader = XmlReader.Create(sr)) 
      { 
       // Move to ROOT Element 
       reader.MoveToContent(); 
       Debug.Assert(reader.Name == "ArrayOfQMXINVQ_INVENTORYType"); // No assert. 

       // Read to first CHILD Element of the root 
       reader.Read(); // Read to the first child NODE of the root element 
       reader.MoveToContent(); // If that node is whitespace, skip to content. 

       // Read to the FIRST array element of the desired name. 
       if (reader.Name != topLevelElementName) 
        if (!reader.ReadToNextSibling(topLevelElementName)) 
         throw new InvalidOperationException("Not enough elements named " + topLevelElementName); 
       // Now read to the Nth element of the desired name. 
       for (int i = topLevelElementIndex; i > 0; i--) 
        if (!reader.ReadToNextSibling(topLevelElementName)) 
         throw new InvalidOperationException("Not enough elements named " + topLevelElementName); 

       // Process the Nth element as desired. 
       Debug.Assert(reader.NodeType == XmlNodeType.Element && reader.Name == topLevelElementName); 
       using (var subReader = reader.ReadSubtree()) 
       { 
        var element = XElement.Load(subReader); 
        Debug.WriteLine(element.ToString()); 
        // If each individual array element has manageable size, the easiest way to parse it is to load it into 
        // an XElement with a nested reader, then use Linq to XML 
        Debug.Assert(element.Descendants("BINNUM").Select(e => (string)e).FirstOrDefault() == "B-8-1"); // No assert. 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      // Handle errors in the file however you like. 
      Debug.WriteLine(ex); 
      throw; 
     } 

Пример fiddle.

0

Проблема заключается в том, что код должен вызывать MoveToFirstAttribute перед входом в цикл while.

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