【问题标题】:System.Xml.XmlException 'Data at the root level is invalid, line 1, position 1' error is showing up when i changed from 1 xml file to 5System.Xml.XmlException '根级别的数据无效,第 1 行,位置 1' 当我从 1 个 xml 文件更改为 5 时出现错误
【发布时间】:2021-04-24 19:22:24
【问题描述】:

大家好,最近我一直在制作 ac# 应用程序来读取 xml 文件并且它可以工作,但现在我的任务是让它这样做并从某个文件夹内的多个 xml 文件中读取某些节点,现在我不工作了并在标题中显示该错误。

using System;
using System.Xml;
using System.IO;
namespace XmlReaderConsoleAPP
{
    class Program
    {
       
        static void Main()
        {
            ProcessFile(@"C:\XMLFiles\SaintGobain_Pam_20210118.xml");
            try
            {
               
                var path = @"C:\XMLFiles\SaintGobain_Pam_20210118.xml";
                DirectoryInfo di = new DirectoryInfo(path);

                foreach (var file in Directory.GetFiles(path))
                {
                   
                }
                Console.ReadKey();
            }
             catch(Exception ex)
            {

                Console.WriteLine("Erro: {0}", ex.Message);
                return;
            }

            static void ProcessFile(string Filename)
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(Filename);
                XmlNodeList xnLista = xml.SelectNodes(@"//ImportSession/Batches/batch/Documents/Document/Pages/Page");
                Console.WriteLine($"Selected {xnLista.Count} nodes");
                int i = 0;

                foreach (XmlNode xn in xnLista)
                {

                    Console.WriteLine($"{++i} {xn.Name}: {xn.Attributes["ImportFileName"].Value}");



                }

                XmlNodeList xnLista2 = xml.SelectNodes(@"//IndexFields/IndexField");
                Console.WriteLine($"Selected {xnLista2.Count} nodes");
               int j = 0;
                foreach (XmlNode xn in xnLista2)
                {


                    Console.WriteLine($"{++j} {xn.Name}: {xn.Attributes["Value"].Value}");

                    //string error = xn.Attributes["ErrorMessage"]?.Value;
                    //if (string.IsNullOrEmpty(error))
                    //{



                    //}

                    //elsex
                    //{


                    //}
                }
                Console.WriteLine(Filename);
            }

           
        }
    }
}

如果你们发现错误,请帮助我,因为我需要它。 ps:xml文件同根ImportSession/Batches/Batch/Documents/Document/Pages/Page

【问题讨论】:

  • 程序的结构似乎有点不对劲。您可能希望从 main 方法中提取 ProcessFile 方法(如果这不仅仅是复制和粘贴错误)。然后,您似乎两次处理同一个文件。一旦硬编码,然后再次进入循环(我建议使用 EnumerateFiles,顺便说一句)。但是,在循环内部,什么都没有发生?不太对,我猜。
  • @Fildor 更糟糕的是,OP 只处理文件一次,整个循环在这里毫无意义,因为 XML 内部存在一个尚未提供的问题。
  • @Tiago 请检查您的代码,逐行慢慢调试。还要检查您在第 1 行指定的文件的内容,我认为它不是有效的 XML
  • @DavidG “但在循环内部,什么都没有发生?我猜不太对。” - 我意识到了这一点。 :)
  • @Fildor 你说 OP 正在处理文件两次,我只是说这不是真的。

标签: c# xml xml-parsing


【解决方案1】:

让我们先清理一下:

namespace XmlReaderConsoleAPP
{
    class Program
    {
        static void Main()
        {
                var path = @"C:\XMLFiles";
                var filter = @"*.xml"; // Add filter to only enumerate .xml files

                foreach (var file in Directory.EnumerateFiles(path, filter))
                {
// Move try/catch inside the loop to skip errornous files.
                   try
                   {
                       ProcessFile( file );
                   }
                   catch(Exception ex) // Usually, try to catch the specific as possible
                   {
                        Console.WriteLine("Error: {0} {1}in File {2}", 
                                            ex.Message, Environment.NewLine, file);
                   }
                }
                Console.ReadKey();
            }
        } // End of Main

            static void ProcessFile(string Filename)
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(Filename);
                XmlNodeList xnLista = xml.SelectNodes(@"//ImportSession/Batches/batch/Documents/Document/Pages/Page");
                Console.WriteLine($"Selected {xnLista.Count} nodes");
                int i = 0;

                foreach (XmlNode xn in xnLista)
                {
                    Console.WriteLine($"{++i} {xn.Name}: {xn.Attributes["ImportFileName"].Value}");
                }

                XmlNodeList xnLista2 = xml.SelectNodes(@"//IndexFields/IndexField");
                Console.WriteLine($"Selected {xnLista2.Count} nodes");
               int j = 0;
                foreach (XmlNode xn in xnLista2)
                {
                    Console.WriteLine($"{++j} {xn.Name}: {xn.Attributes["Value"].Value}");
                }
                Console.WriteLine(Filename);
            }
           
    } // class
} // namespace

下一步:System.Xml.XmlException 表示 xml 输入文件有问题。

你能做些什么呢?

  • 跳过它,这样其他的可能仍会被处理。记录错误,以便您以后深入研究文件,或请求修复并再次发送。

  • 如果你有一个 XML Schema,你可以验证 xml 并且更容易找到究竟是什么错误。请参阅XML schema (XSD) validation with XmlSchemaSet 和/或XmlDocument.Validate Method

  • 您可以手动检查输入文件并找出错误。请注意,该信息有时可能具有欺骗性。我会先检查它是否格式正确且有效的 xml(有相应的工具)。

【讨论】:

  • 你好 Fildor 我让它工作了,现在它显示了我需要的一切,但猜猜我现在需要做什么,就好像它只显示信息作为其中的特定信息,例如错误和批处理将其节点为 Processed = to 1 你也可以帮助我吗? ps:你帮了大忙。
  • 当然,只需发布​​一个包含更新代码和新要求的新问题,我们就会知道您的问题出在哪里。
【解决方案2】:

我能够解决对象及其序列化的问题。 您可以通过以下两个帖子找到一种方法:

对象:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/objects

对象序列化:https://docs.microsoft.com/en-us/dotnet/standard/serialization/how-to-serialize-an-object

提供更多上下文。

首先在您正在执行的方法的开头创建空字符串,它是 foreach 循环或 if 语句

class Program
{
    static DataAccess da = new DataAccess();

    public static void Main()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ImportSession));

        foreach (string filename in Directory.EnumerateFiles(Properties.Settings.Default.PastaXML, "*.xml"))
        {
            string fName = "";
            string BatchCName = "";
            string batchName = "";
            string description = "";

            ProcessFile(filename, serializer, fName, BatchCName, batchName, description );
        }

        Console.ReadKey();
    }
}

在我的情况下开始我的processfile函数

private static void ProcessFile(string filename, XmlSerializer serializer, string fName, string batchName, string description, string BatchCName)
    {
        Console.WriteLine("A processar xml: " + filename);
        bool temErro = false;
       
        using (FileStream file = File.OpenRead(filename))
        {
            var session = (ImportSession)serializer.Deserialize(file);
     
            foreach (Batch batch in session.Batches)
            {
                fName = Path.GetFileName(filename);
                BatchCName = batch.BatchClassName;
                batchName = batch.Name;
                description = batch.Description;
                foreach (Document doc in batch.Documents)
                {
                    foreach (Page page in doc.Pages)
                    {
            @            if (!string.IsNullOrEmpty(batch.Processed.ToString()))
                        {
                            if (page.HasError)
                            {
                               
                                string Import = page.ImportFileName;
                                Console.WriteLine("Página com erro:" + Import + fName);
                                temErro = true;                                
                                da.SP_Insert(filename,fName,BatchCName,batchName,description,1,Import,0, "");

这个 processfile 中有两个 if 语句,用于检查文件中是否存在错误以及文件是否已被处理。

我还在存储过程中添加了 Insert 以确保在我正在进行的编辑中所有内容都已完成。

我使用的对象如下

public class ImportSession
{
    public Batch[] Batches { get; set; }
}

public class Batch
{
    [XmlAttribute]
    public string Name { get; set; }
    [XmlAttribute]
    public string Description { get; set; }
    [XmlAttribute]
    public string BatchClassName { get; set; }
    [XmlAttribute]
    public bool Processed { get; set; }
    public Document[] Documents { get; set; }
}

public class Document
{
    [XmlAttribute]
    public string FormTypeName { get; set; }
    public IndexField[] IndexFields { get; set; }
    public Page[] Pages { get; set; }
}

public class IndexField
{
    [XmlAttribute]
    public string Name { get; set; }
    [XmlAttribute]
    public string Value { get; set; }
}

public class Page
{
    [XmlAttribute]
    public string ImportFileName { get; set; }
    [XmlAttribute]
    public string ErrorCode { get; set; }
    [XmlAttribute]
    public string ErrorMessage { get; set; }
    [XmlIgnore]
    public bool HasError => !string.IsNullOrWhiteSpace(ErrorMessage);
}

我的存储过程插入以防你们中的任何人想知道如何去做

public void SP_Insert(string XMLPath, string XMLName, string BatchClassName, string BatchName,
        string BatchDescription, int Error, string ErrorImagePath, int Done, string DonePath)
    {

        try
        {
            ManageConnectionState();
            SqlCommand command = new SqlCommand("Sp_Insert", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add("@XMLPath",SqlDbType.NText).Value = XMLPath;
            command.Parameters.Add("@XMLName",SqlDbType.NText).Value = XMLName;
            command.Parameters.Add("@BatchClassName",SqlDbType.NText).Value= BatchClassName;
            command.Parameters.Add("@BatchName",SqlDbType.NText ).Value = BatchName;
            command.Parameters.Add("@BatchDescription", SqlDbType.NText ).Value = BatchDescription;
            command.Parameters.Add("@Error",SqlDbType.Bit).Value = Error;
            command.Parameters.Add("@ErrorImagePath", SqlDbType.NText).Value = ErrorImagePath;
            command.Parameters.Add("@Done", SqlDbType.Bit ).Value=Done;
            command.Parameters.Add("@DonePath", SqlDbType.NText).Value = DonePath;
            command.ExecuteScalar();


        }
        catch (Exception ex)
        {
            Console.WriteLine("Erro: " + ex.Message);
        }
        finally
        {
            ManageConnectionState();
            connection.Close();
        }
    }

如果有不明白的地方请评论帮忙。

【讨论】:

  • 很好,你为此付出了很多努力。还有一些小的格式问题,我会看看那些,也许你也可以纠正。对于前两个 sn-ps:我不明白为什么需要这么多函数参数。据我所知,您只需要序列化程序和文件名。其余的参数,您可以在被调用的函数内创建为本地变量。
  • @Fildor ye 我有点做过,但是当我掌握了我在做什么并且在你和其他人的帮助下,我有点适应它并且它结束了工作,请告诉我我怎么能改进它
  • 好的,所以 ProcessFile 实际上只需要 private static void ProcessFile(string filename, XmlSerializer serializer) 。然后你可以将string fName = ""; ... string description = ""; 移动到ProcessFile 方法中。只需将这些作为函数内的第一行即可。
  • @Fildor 我不想说你的错误,但不会改变我的 dataAccess 文件的制作方式,因为我从那里调用了 processfile 并且我拥有来自它们的所有变量
  • 不。所有这些都设置在函数内部。据我从您的答案中的代码可以看出,在这里。
猜你喜欢
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-28
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多