【问题标题】:Why is xml declaration getting deleted while parsing?为什么解析时xml声明被删除?
【发布时间】:2017-11-30 13:24:31
【问题描述】:

我正在尝试使用以下程序将某个节点值从一个 xml 文件修改为另一个,该程序从名为 的文件夹中的 xml 文件中获取第一个节点 pub-title 的值>abc,然后将值粘贴到名为 xyz 的文件夹中另一个 xml 文件中的第一个节点 publisher-name

注意:escape_string 方法被实现为不修改 UTF-8 实体值并保持原样。

var job_folders = Directory.EnumerateDirectories(textBox1.Text, "*", SearchOption.TopDirectoryOnly);
foreach (string job_folder in job_folders)
{
    var target_xml_file = Directory.GetFiles(job_folder, "*.xml", SearchOption.AllDirectories).Where(a => Path.GetFileName(Path.GetDirectoryName(x)).ToLower() == "abc").First();
    var target_meta_file = Directory.GetFiles(job_folder, "*.xml", SearchOption.AllDirectories).Where(a => Path.GetFileName(Path.GetDirectoryName(x)).ToLower() == "xyz").First();

    string path = Path.GetFullPath(target_meta_file);
    string file_content = escape_string(File.ReadAllText(path), 0);
    XDocument doc = XDocument.Parse(file_content, LoadOptions.PreserveWhitespace);
    var lbl=doc.Descendants("pub-title").First().Value;
    XDocument doc2 = XDocument.Parse(escape_string(File.ReadAllText(target_xml_file), 0), LoadOptions.PreserveWhitespace);
    doc2.DocumentType.InternalSubset = null;
    doc2.Descendants("publisher-name").First().Value=lbl;
    doc2.Save(target_xml_file);
    File.WriteAllText(target_xml_file, escape_string(doc2.ToString(), 1));
}

MessageBox.Show("Complete");

private static string escape_string(string input_string, int option)
{
    switch (option)
    {
        case 0:
            return input_string.Replace("&", "&").ToString();
        case 1:
            return input_string.Replace("&", "&").ToString();
        default:
            return null;
    }
}

一切正常,但 <?xml version="1.0" encoding="utf-8"?> 正在从 target_xml_file 中的文件中删除。

我该如何解决这个问题? 修改前的文件

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="jats-html.xsl"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD with OASIS Tables v1.0 20120330//EN" "JATS-journalpublishing-oasis-article1.dtd"[]>
<article article-type="proceedings" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:oasis="http://www.niso.org/standards/z39-96/ns/oasis-exchange/table">
<front>
<journal-meta>
<journal-id journal-id-type="publisher-id" />
<journal-title-group>
<journal-title>Eleventh &#x0026; Tenth International Conference on Correlation Optics</journal-title>
</journal-title-group>
<issn pub-type="epub">0277-786X</issn>
<publisher>
<publisher-name>SPIE</publisher-name>
</publisher>
</journal-meta>
....
....

之后的文件

<?xml-stylesheet type="text/xsl" href="jats-html.xsl"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD with OASIS Tables v1.0 20120330//EN" "JATS-journalpublishing-oasis-article1.dtd">
<article article-type="proceedings" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:oasis="http://www.niso.org/standards/z39-96/ns/oasis-exchange/table">
<front>
<journal-meta>
<journal-id journal-id-type="publisher-id" />
<journal-title-group>
<journal-title>Eleventh &#x0026; Tenth International Conference on Correlation Optics</journal-title>
</journal-title-group>
<issn pub-type="epub">0277-786X</issn>
<publisher>
<publisher-name>a</publisher-name>
</publisher>
</journal-meta>

【问题讨论】:

  • 为什么要保存文件两次,第二次保存为 tekst 而不是 xml 文件?如果在doc2.Save(target_xml_file); 之后删除File.WriteAllText(target_xml_file, escape_string(doc2.ToString(), 1)); 会发生什么?
  • XDocument.ToString() 不包括 XML 声明。它在 .Declaration 属性中明确可用。
  • @JeroenMostert 那我该怎么办?
  • @oerkelens 如果我删除File.WriteAllText(target_xml_file, escape_string(doc2.ToString(), 1));,那么像&amp;amp;#x2014; 这样的UTF-8 代码会像&amp;amp;#x2014; 一样保留。我需要使用escape_string 方法将其恢复为&amp;amp;#x2014;跨度>
  • 但是你为什么还要尝试doc2.Save(target_xml_file);呢?您是否查看过之后会发生什么,或者您是否只是在第一次将文件保存为 XML 文档后才尝试再次覆盖该文件?

标签: c# xml


【解决方案1】:

按照XDocument.ToString() drops XML Encoding Tag 的答案,您不应该使用ToString 方法,而是使用StringWriter

using (var stream = new MemoryStream())
{
    using (var writer = new XmlTextWriter(stream, Encoding.UTF8))
    {
        doc2.Save(writer);
    }
    string xml = escape_string(Encoding.UTF8.GetString(stream.ToArray()), 1);
    File.WriteAllBytes(target_xml_file, Encoding.UTF8.GetBytes(xml));
}

【讨论】:

  • 现在&lt;?xml version="1.0" encoding="utf-8"?&gt; 正在转换为&lt;?xml version="1.0" encoding="utf-16"?&gt;
  • @Don_B 这是因为 C# 中的字符串是 unicode 或 utf-16 编码的。如果您想要 utf-8 编码,您可以使用 XmlTextWriter 并提供 Encoding.UTF8 作为第二个参数。但是您必须写入文件或流,因为字符串也是 utf-16。
  • @Don_B 只需创建一个继承自 StringWriter 的新字符串编写器并覆盖编码 (public override Encoding Encoding =&gt; Encoding.UTF8;)
  • @Don_B,你确定需要使用escape_string吗?好像不太对。
  • @AndriiLitvinov 我还能如何在文件中保持&amp;#x002A;, &amp;#x0026; ..etc 之类的代码不变?
【解决方案2】:

为什么不在进程后简单地添加一个XDeclaration 方法,比如

new XDeclaration("1.0", "utf-8", null)

然后保存文件。只需要两行代码。

【讨论】:

  • 看到这个答案被接受有点惊讶,因为 UTF-8 编码只会在保存文档时使用,这会阻止 escape_string 中的后处理。当使用doc.ToString 时,无论如何都会剥离声明。更多的编码将是 UTF-16,而不是 UTF-8。按照这种思维方式,只需在结果字符串前面加上 "&lt;?xml version="1.0" encoding="utf-8"?&gt;" 就更容易了。
  • @AndriiLitvinov 在结果字符串前面加上"&lt;?xml version="1.0" encoding="utf-8"?&gt;" 是什么意思?在调用doc.ToString 方法时不会也被删除吗?
  • 我的意思是来自 OP 的代码示例的 "&lt;?xml version="1.0" encoding="utf-8"?&gt;" + escape_string(doc2.ToString(), 1)
  • 这会起作用,但您建议的解决方案不会。它实际上并没有改变任何东西,因为在解析原始 xml 文档后,XDcoument 中有 xml 声明。
猜你喜欢
  • 1970-01-01
  • 2013-10-16
  • 2023-03-25
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多