【问题标题】:XMLReader.ReadToNextSibling jumps to end of fileXMLReader.ReadToNextSibling 跳转到文件末尾
【发布时间】:2015-07-17 17:31:11
【问题描述】:

我在 C# 中使用 XMLReader 从作为 Web 请求的一部分接收的 XML 文档中获取数据。 XML 是根据传递给服务的查询参数生成的,并且可以包含无数元素。此问题中的示例基于库存查询。

这是 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();

顶层代码(未显示)将子元素读取到数据表中。如果遇到子子项,则执行包含的代码。找到第一个子元素的子元素并成功添加到数据表中。

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

随后的执行会导致阅读器直接跳到文件的末尾。关于为什么要使用 EOF 而不是阅读下一个孩子的任何想法?

【问题讨论】:

    标签: c# xml xmlreader


    【解决方案1】:

    您将阅读器定位在root element "ArrayOfQMXINVQ_INVENTORYType",然后尝试阅读其下一个兄弟。但是根元素不能有兄弟姐妹,因为只能有一个。你想做的是:

    • 移动到根元素
    • 读给它的第一个孩子。
    • 跳到名为topLevelElementName 的根的第K 个子元素。
    • 搜索其子元素。

    例如:

            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

    【讨论】:

      【解决方案2】:

      问题是代码应该在进入while循环之前调用MoveToFirstAttribute。

      【讨论】:

        猜你喜欢
        • 2020-02-21
        • 1970-01-01
        • 2017-10-22
        • 2019-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多