gpt4 book ai didi

c# - XDocument.Save() 删除了我的 实体

转载 作者:数据小太阳 更新时间:2023-10-29 01:49:38 25 4
gpt4 key购买 nike

我使用 C# 和 Linq-to-XML 编写了一个工具来修复一些 XML 文件(即,插入一些丢失的属性/值)。该工具将现有的 XML 文件加载到 XDocument 对象中。然后,它通过节点向下解析以插入丢失的数据。之后,它调用 XDocument.Save() 将更改保存到另一个目录。

所有这些都很好,除了一件事:XML 文件文本中的任何 实体都被换行符替换。当然,该实体代表一个新行,但我需要在 XML 中保留该实体,因为另一个消费者需要它。

有没有办法在不丢失 实体的情况下保存修改后的XDocument?

谢谢。

最佳答案


实体在 XML 中在技术上称为“数字字符引用”,当原始文档加载到 XDocument 中时,它们将被解析。 .这使您的问题难以解决,因为在 XDocument 之后无法区分已解析的空白实体和无关紧要的空白(通常用于为纯文本查看器格式化 XML 文档)。已加载。因此,以下内容仅适用于您的文档没有任何无关紧要的空格的情况。

System.Xml库允许通过设置 NewLineHandling 来保留空白实体XmlWriterSettings 的属性(property)类别为 Entitize .但是,在文本节点中,这只会实体化 \r
 ,而不是 \n
 .

最简单的解决方案是派生自 XmlWriter类并覆盖它的 WriteString 用数字字符实体手动替换空白字符的方法。 WriteString方法也恰好是 .NET 实体化不允许出现在文本节点中的字符的地方,例如语法标记 & , < , 和 > , 分别实体化为 &amp; , &lt; , 和 &gt; .

XmlWriter是抽象的,我们将派生自XmlTextWriter为了避免必须实现前一个类的所有抽象方法。这是一个快速而肮脏的实现:

public class EntitizingXmlWriter : XmlTextWriter
{
public EntitizingXmlWriter(TextWriter writer) :
base(writer)
{ }

public override void WriteString(string text)
{
foreach (char c in text)
{
switch (c)
{
case '\r':
case '\n':
case '\t':
base.WriteCharEntity(c);
break;
default:
base.WriteString(c.ToString());
break;
}
}
}
}

如果打算在生产环境中使用,您需要取消 c.ToString()部分,因为它非常低效。您可以通过批处理原始 text 的子字符串来优化代码不包含任何要实体化的字符,并将它们一起放入单个 base.WriteString打电话。

一个警告:下面的简单实现是行不通的,因为基数 WriteString方法将替换任何 &带有 &amp; 的字符,从而导致\r将扩展为 &amp;#xA; .

    public override void WriteString(string text)
{
text = text.Replace("\r", "&#xD;");
text = text.Replace("\n", "&#xA;");
text = text.Replace("\t", "&#x9;");
base.WriteString(text);
}

最后,保存你的XDocument到目标文件或流中,只需使用以下代码段:

using (var textWriter = new StreamWriter(destination))
using (var xmlWriter = new EntitizingXmlWriter(textWriter))
document.Save(xmlWriter);

希望这对您有所帮助!

编辑:作为引用,这里是重写 WriteString 的优化版本方法:

public override void WriteString(string text)
{
// The start index of the next substring containing only non-entitized characters.
int start = 0;

// The index of the current character being checked.
for (int curr = 0; curr < text.Length; ++curr)
{
// Check whether the current character should be entitized.
char chr = text[curr];
if (chr == '\r' || chr == '\n' || chr == '\t')
{
// Write the previous substring of non-entitized characters.
if (start < curr)
base.WriteString(text.Substring(start, curr - start));

// Write current character, entitized.
base.WriteCharEntity(chr);

// Next substring of non-entitized characters tentatively starts
// immediately beyond current character.
start = curr + 1;
}
}

// Write the trailing substring of non-entitized characters.
if (start < text.Length)
base.WriteString(text.Substring(start, text.Length - start));
}

关于c# - XDocument.Save() 删除了我的 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8811873/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com