System.Xml.XmlException '根级别的数据无效,第 1 行,位置 1' 当我从 1 个 xml 文件更改为 5 时出现错误

Posted

技术标签:

【中文标题】System.Xml.XmlException \'根级别的数据无效,第 1 行,位置 1\' 当我从 1 个 xml 文件更改为 5 时出现错误【英文标题】: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 正在处理文件两次,我只是说这不是真的。 【参考方案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 1in 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 并且我拥有来自它们的所有变量 不。所有这些都设置在函数内部。据我从您的答案中的代码可以看出,在这里。

以上是关于System.Xml.XmlException '根级别的数据无效,第 1 行,位置 1' 当我从 1 个 xml 文件更改为 5 时出现错误的主要内容,如果未能解决你的问题,请参考以下文章

System.Xml.XmlException:“':'字符,十六进制值 0x3A,不能包含在名称中。”

Web 服务调用导致 System.Xml.XmlException:'.',十六进制值 0x00

System.Xml.XmlException '根级别的数据无效,第 1 行,位置 1' 当我从 1 个 xml 文件更改为 5 时出现错误

System.Xml.XmlException: “=”是意外的标记。标记应为“;”

如果 XmlException.SourceUri 是只读的,那有啥好处?

检测 XML 的更好方法?