如何读取带有 "Unexpected XML declaration" 的 XML 文件?
How to read a XML file with a "Unexpected XML declaration"?
我读取 zip 文件中 XML 文件的代码:
"ZipPathListSize"是zip文件的个数,@ZipPathList[i]是一个字符串数组,每个zip文件的路径, "modDesc / modDesc.xml" 是每个 zip 文件中 XML 文件的固定名称。
using System.IO.Compression;
using System.Xml;
--------------------------------------------
for (int i = 0; i < ZipPathListSize; i++)
{
using (ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i]))
{
XmlDocument ModDesc = new();
ZipArchiveEntry Entry = ZipFileContent.GetEntry("modDesc.xml");
if (Entry != null)
{
using (Stream stream = Entry.Open())
{
bool ExFlag = false;
try
{
ModDesc.Load(stream);
}
catch (Exception ex)
{
MessageBox.Show(Convert.ToString(@ZipPathList[i] + ex));
ExFlag = true;
}
finally
{
if (ExFlag == false)
{
XmlNode MVersion = ModDesc.DocumentElement.SelectSingleNode("/modDesc");
int Version = Convert.ToInt16(MVersion.Attributes["descVersion"].InnerText);
//MessageBox.Show(@ZipPathList[i] + Version); //DEBUG ONLY
}
}
}
}
else
{
MessageBox.Show("Not A Mod"); //DEBUG ONLY
}
}
}
问题是,zip 文件中的一些 XML 文件 (modDesc.xml) 没有正确的声明。如:
空第一行
<!-- This is an empty line (Line 1), in the origin file -->
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!-- Here is Line 2 -->
<modDesc descVersion="61">
...
或版本错误
<?xml version="1.1" encoding="utf-8" standalone="no" ?> <!-- 1.1? Really? -->
<modDesc descVersion="62">
但是 XML 的所有其他部分都是正确的。
如何读取声明错误的 XML?也许以某种方式忽略格式检查并强制它读取节点和属性?
顺便说一句,我无法手动修改任何XML文件或以非编程方式修复它们。
所以,没有 vscode,没有记事本++ :(
System.Xml.XmlException: The XML declaration must be the first node in the document, and no whitespace characters are allowed to appear before it. Line 2, position 3.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParsePI(StringBuilder piInDtdStringBuilder)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(Stream inStream)
at FS22_ModManagerCore.ListMods.ByModFolder(String ModFolder) in
.....ListMods.cs:line 37
System.Xml.XmlException: Version number '1.1' is invalid. Line 1, position 16.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl)
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(Stream inStream)
at FS22_ModManagerCore.ListMods.ByModFolder(String ModFolder) in
......ListMods.cs:line 37
至于目前,我已经自己解决了这个问题,我将post我的代码放在这里供一般参考。
要解决 XML 声明问题,首先我 Dispose()
ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i])
和 re-open 它在 ZipArchiveMode.Update
.
然后将 modDesc.xml 中的所有文本加载到 string[] AllTextInLine
。
之后,使用 ErrorZipContent.CreateEntry("modDesc.xml")
删除并重新创建 modDesc.xml。
最后把正确的第一行(声明)写到新的modDesc.xml,把剩下的写到AllTextInLine[]
。
for (int i = 0; i < ZipPathListSize; i++)
{
using (ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i]))
{
XmlDocument ModDesc = new();
ZipArchiveEntry NormalEntry = ZipFileContent.GetEntry("modDesc.xml");
if (NormalEntry != null)
{
Stream NormalStream = NormalEntry.Open();
bool ExFlag = false;
try
{
ModDesc.Load(NormalStream);
}
catch (Exception ex)
{
ExFlag = true;
MessageBox.Show(Convert.ToString(@ZipPathList[i] + "\n\n" + ex));
Clipboard.SetText(Convert.ToString(@ZipPathList[i] + "\n\n" + ex));
MessageBox.Show("Try to fix" + "\n\n" + @ZipPathList[i]);
//ReplaceXmlDeclaration
ZipFileContent.Dispose();
using (ZipArchive ErrorZipContent = ZipFile.Open(@ZipPathList[i], ZipArchiveMode.Update))
{
ZipArchiveEntry ErrorZipEntry = ErrorZipContent.GetEntry("modDesc.xml");
string[] AllTextInLine;
using (var reader = new StreamReader(ErrorZipEntry.Open()))
{
AllTextInLine = Convert.ToString(reader.ReadToEnd()).Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
}
//MessageBox.Show(AllTextInLine[0] + AllTextInLine[1] + AllTextInLine[2]); //DEBUG ONLY
string Declaration = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\" ?>";
if (AllTextInLine[0] != Declaration)
{
ErrorZipEntry.Delete();
ErrorZipEntry = ErrorZipContent.CreateEntry("modDesc.xml");
using (var writer = new StreamWriter(ErrorZipEntry.Open()))
{
writer.WriteLine(Declaration); //Line 1
MessageBox.Show(@ZipPathList[i]); //DEBUG ONLY
for (int j = 1; j < AllTextInLine.Length; j++) //Start with Line 2 (Index j=1)
{
if (!AllTextInLine[j].Trim().StartsWith("<?"))
{
writer.WriteLine(AllTextInLine[j]);
}
}
}
}
ExFlag = false;
try
{
ModDesc.Load(ErrorZipEntry.Open());
}
catch (Exception exagain)
{
ExFlag = true;
MessageBox.Show(Convert.ToString(exagain));
}
}
}
finally
{
if (ExFlag == false)
{
XmlNode MVersion = ModDesc.DocumentElement.SelectSingleNode("/modDesc");
int Version = Convert.ToInt16(MVersion.Attributes["descVersion"].InnerText);
//MessageBox.Show(@ZipPathList[i] + Version); //DEBUG ONLY
//if (i == ZipPathListSize - 1) //.
//{ //.
// MessageBox.Show(@ZipPathList[i] + Version); //.
//} //DEBUG ONLY
}
else
{
MessageBox.Show("Fix Attempt Filed");
}
}
}
else
{
MessageBox.Show("Not A Mod"); //DEBUG ONLY
}
}
}
我读取 zip 文件中 XML 文件的代码:
"ZipPathListSize"是zip文件的个数,@ZipPathList[i]是一个字符串数组,每个zip文件的路径, "modDesc / modDesc.xml" 是每个 zip 文件中 XML 文件的固定名称。
using System.IO.Compression;
using System.Xml;
--------------------------------------------
for (int i = 0; i < ZipPathListSize; i++)
{
using (ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i]))
{
XmlDocument ModDesc = new();
ZipArchiveEntry Entry = ZipFileContent.GetEntry("modDesc.xml");
if (Entry != null)
{
using (Stream stream = Entry.Open())
{
bool ExFlag = false;
try
{
ModDesc.Load(stream);
}
catch (Exception ex)
{
MessageBox.Show(Convert.ToString(@ZipPathList[i] + ex));
ExFlag = true;
}
finally
{
if (ExFlag == false)
{
XmlNode MVersion = ModDesc.DocumentElement.SelectSingleNode("/modDesc");
int Version = Convert.ToInt16(MVersion.Attributes["descVersion"].InnerText);
//MessageBox.Show(@ZipPathList[i] + Version); //DEBUG ONLY
}
}
}
}
else
{
MessageBox.Show("Not A Mod"); //DEBUG ONLY
}
}
}
问题是,zip 文件中的一些 XML 文件 (modDesc.xml) 没有正确的声明。如:
空第一行
<!-- This is an empty line (Line 1), in the origin file -->
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!-- Here is Line 2 -->
<modDesc descVersion="61">
...
或版本错误
<?xml version="1.1" encoding="utf-8" standalone="no" ?> <!-- 1.1? Really? -->
<modDesc descVersion="62">
但是 XML 的所有其他部分都是正确的。
如何读取声明错误的 XML?也许以某种方式忽略格式检查并强制它读取节点和属性?
顺便说一句,我无法手动修改任何XML文件或以非编程方式修复它们。
所以,没有 vscode,没有记事本++ :(
System.Xml.XmlException: The XML declaration must be the first node in the document, and no whitespace characters are allowed to appear before it. Line 2, position 3.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParsePI(StringBuilder piInDtdStringBuilder)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(Stream inStream)
at FS22_ModManagerCore.ListMods.ByModFolder(String ModFolder) in
.....ListMods.cs:line 37
System.Xml.XmlException: Version number '1.1' is invalid. Line 1, position 16.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl)
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(Stream inStream)
at FS22_ModManagerCore.ListMods.ByModFolder(String ModFolder) in
......ListMods.cs:line 37
至于目前,我已经自己解决了这个问题,我将post我的代码放在这里供一般参考。
要解决 XML 声明问题,首先我 Dispose()
ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i])
和 re-open 它在 ZipArchiveMode.Update
.
然后将 modDesc.xml 中的所有文本加载到 string[] AllTextInLine
。
之后,使用 ErrorZipContent.CreateEntry("modDesc.xml")
删除并重新创建 modDesc.xml。
最后把正确的第一行(声明)写到新的modDesc.xml,把剩下的写到AllTextInLine[]
。
for (int i = 0; i < ZipPathListSize; i++)
{
using (ZipArchive ZipFileContent = ZipFile.OpenRead(@ZipPathList[i]))
{
XmlDocument ModDesc = new();
ZipArchiveEntry NormalEntry = ZipFileContent.GetEntry("modDesc.xml");
if (NormalEntry != null)
{
Stream NormalStream = NormalEntry.Open();
bool ExFlag = false;
try
{
ModDesc.Load(NormalStream);
}
catch (Exception ex)
{
ExFlag = true;
MessageBox.Show(Convert.ToString(@ZipPathList[i] + "\n\n" + ex));
Clipboard.SetText(Convert.ToString(@ZipPathList[i] + "\n\n" + ex));
MessageBox.Show("Try to fix" + "\n\n" + @ZipPathList[i]);
//ReplaceXmlDeclaration
ZipFileContent.Dispose();
using (ZipArchive ErrorZipContent = ZipFile.Open(@ZipPathList[i], ZipArchiveMode.Update))
{
ZipArchiveEntry ErrorZipEntry = ErrorZipContent.GetEntry("modDesc.xml");
string[] AllTextInLine;
using (var reader = new StreamReader(ErrorZipEntry.Open()))
{
AllTextInLine = Convert.ToString(reader.ReadToEnd()).Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
}
//MessageBox.Show(AllTextInLine[0] + AllTextInLine[1] + AllTextInLine[2]); //DEBUG ONLY
string Declaration = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\" ?>";
if (AllTextInLine[0] != Declaration)
{
ErrorZipEntry.Delete();
ErrorZipEntry = ErrorZipContent.CreateEntry("modDesc.xml");
using (var writer = new StreamWriter(ErrorZipEntry.Open()))
{
writer.WriteLine(Declaration); //Line 1
MessageBox.Show(@ZipPathList[i]); //DEBUG ONLY
for (int j = 1; j < AllTextInLine.Length; j++) //Start with Line 2 (Index j=1)
{
if (!AllTextInLine[j].Trim().StartsWith("<?"))
{
writer.WriteLine(AllTextInLine[j]);
}
}
}
}
ExFlag = false;
try
{
ModDesc.Load(ErrorZipEntry.Open());
}
catch (Exception exagain)
{
ExFlag = true;
MessageBox.Show(Convert.ToString(exagain));
}
}
}
finally
{
if (ExFlag == false)
{
XmlNode MVersion = ModDesc.DocumentElement.SelectSingleNode("/modDesc");
int Version = Convert.ToInt16(MVersion.Attributes["descVersion"].InnerText);
//MessageBox.Show(@ZipPathList[i] + Version); //DEBUG ONLY
//if (i == ZipPathListSize - 1) //.
//{ //.
// MessageBox.Show(@ZipPathList[i] + Version); //.
//} //DEBUG ONLY
}
else
{
MessageBox.Show("Fix Attempt Filed");
}
}
}
else
{
MessageBox.Show("Not A Mod"); //DEBUG ONLY
}
}
}