微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我无法将数据从 XML 文件移动到具有 CDATA 节点类型的 ARRAY

如何解决我无法将数据从 XML 文件移动到具有 CDATA 节点类型的 ARRAY

根据标题,从包含 CDATA 元素的 XML 文件获取数据到数组中时遇到问题。 基于我目前对如何做的有限了解,我想出了这个基本的工作方法 CDATA 很奇怪,所以我的常规方法不起作用。我找到节点的正常路线并没有停在它们上面,然后是整个 CDATA 问题。

XmlTextReader xmlReader = new XmlTextReader(FilePath);
while (xmlReader.Read())
{
    // Position the reader on the OrderNumber node
    xmlReader.ReadToFollowing("quoteNumber");
    XmlReader inner = xmlReader.ReadSubtree();
    while (inner.Read())
    {
        switch (xmlReader.NodeType)
        {
            case XmlNodeType.CDATA:
                Globals.COData[0] = inner.Value;
                break;
        }
    }

    xmlReader.ReadToFollowing("orderNumber");
    inner = xmlReader.ReadSubtree();
    while (inner.Read())
    {
        switch (xmlReader.NodeType)
        {
            case XmlNodeType.CDATA:
                Globals.COData[1] = inner.Value;
                break;
        }
    }

但是我有很多数据元素要获取并假设有更好的方法文件看起来像:

Image of XML

以及相关部分:

<quoteNumber>
<![CDATA[ John Test 123]]>
</quoteNumber>
<orderNumber>
<![CDATA[ 1352738]]> 
</orderNumber>

包含的项目在文件末尾有一个结束元素。整个 XML 太大,无法发布。

XML 格式不在我的控制范围内。

我的最终目标是将 OrderNumber 及其值放入一个数组中。还有 Quote number 及其值。我已经习惯看到 <OrderNumber>123</OrderNumber>,所以 CDATA 节点对我来说是新的。

解决方法

由于您没有共享完整的 XML,所以并不完全清楚您哪里出错了,但是您没有从 Read() 循环内部检查 XmlReader.ReadToFollowing(string) 的返回值。因此,一旦你读过了最后一个 <orderNumber>,当没有找到另一个 <quoteNumber> 时,你会得到一个异常。

我建议按如下方式重构您的代码:

var ns = ""; // Replace with @"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
var list = new List<Tuple<string,string>>(); // List of (quoteNumber,orderNumber) values.
var xmlReader = XmlReader.Create(FilePath);
while (xmlReader.ReadToFollowing("quoteNumber",ns))
{
    string quoteNumber = null;
    string orderNumber = null;
    using (var inner = xmlReader.ReadSubtree())
    {
        // We need to skip the insignificant whitespace around the CDATA nodes which ReadElementContentAsString() will not do.
        while (inner.Read())
        {
            switch (xmlReader.NodeType)
            {
                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                    quoteNumber += inner.Value;
                    break;
            }
        }
        // After ReadSubtree() the reader is positioned on the </quoteNumber> element end.
    }
    // If the next orderNumber node is nmissing,ReadToFollowing() will read all the way past the next quoteNumber node.  
    // Use ReadToNextSibling() instead.
    if (xmlReader.ReadToNextSibling("orderNumber",ns))
    {
        using (var inner = xmlReader.ReadSubtree())
        {
            while (inner.Read())
            {
                switch (xmlReader.NodeType)
                {
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA:
                        orderNumber += inner.Value;
                        break;
                }
            }
        }
    }

    if (quoteNumber != null && orderNumber != null)
        list.Add(Tuple.Create(quoteNumber,orderNumber)); 
    else
    {
        // Add error handling here
    }
}

注意事项:

  • CDATA 只是对 XML 字符数据节点进行编码的另一种方式,有关详细信息,请参阅 What does <![CDATA[]]> in XML mean?XmlReader.Value 将包含 XML 字符数据节点的未转义值,无论它是编码为常规文本节点还是 CDATA 节点。

  • 从您的问题中不清楚 XML 文件中是否必须只有一个 <quoteNumber> 节点。因此,我将报价和订单号对读入 List<Tuple<string,string>>。阅读完成后,您可以检查阅读了多少,然后根据需要添加到 Globals.COData

  • XmlReader.ReadToFollowing() 返回

    true 如果找到匹配的元素;否则 falseXmlReader 处于文件结束状态。

    因此需要检查它的返回值以确保您不会尝试读取文件末尾。

  • 您的代码不会尝试处理缺少 <orderNumber> 的情况。如果是,则代码可能会跳过下一个 <quoteNumber> 以读取其订单号。为了避免这种可能性,我使用 XmlReader.ReadToNextSibling() 将搜索范围限制为属于同一父节点的 <orderNumber> 节点。

  • 通过使用 XmlReader.ReadToFollowing("orderNumber"),您可以对代码进行硬编码,以假设 orderNumber 节点没有命名空间前缀。与其这样做,不如明确指出它们所在的命名空间,它似乎类似于 http://intelliquip.com/integrationS...,其中未显示 ... 部分。

    我建议使用 XmlReader.ReadToFollowing("orderNumber",ns),其中 ns 是订单和报价节点实际所在的命名空间。

  • XmlTextReader 自 .Net 2.0 起已弃用。改用 XmlReader.Create()

  • XmlReader API 使用起来相当繁琐。如果您的 XML 文件不大,您可以考虑将它们加载到 XDocument 中并使用 LINQ to XML 进行查询。

    例如,您的 XmlReader 代码可以重写如下:

     var doc = XDocument.Load(FilePath);
     XNamespace ns = ""; // Replace with @"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
     var query = from quote in doc.Descendants(ns + "quoteNumber")
         let order = quote.ElementsAfterSelf(ns + "orderNumber").FirstOrDefault()
         where order != null
         select Tuple.Create(quote.Value,order.Value);
    
     var list = query.ToList();
    

    看起来简单多了。

  • 您也可以考虑用适当的数据模型替换 Tuple<string,string>,例如

    public class Order
    {
        public string QuoteNumber { get; set; }
        public string OrderNumber { get; set; }
    }
    

演示小提琴 #1 here 用于 XmlReader 和 #2 here 用于 LINQ to XML。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。