【问题标题】:How can I convert an XElement to a byte array for a PutFile operation?如何将 XElement 转换为字节数组以进行 PutFile 操作?
【发布时间】:2020-12-16 01:09:38
【问题描述】:

我需要将大的XElement 转换为字节数组,以便以后可以将其上传到文件共享。调用的正确方法是什么?

下面是内部方法fileShare.PutFile 的签名:

void PutFile(string folder, string fileName, byte[] content);

然后给定一个XElement xml,我尝试通过使用Encoding.Default.GetBytes() 对其XElement.Value 进行编码,将其转换为字节数组,如下所示:

byte[] bytes = Encoding.Default.GetBytes(xml.Value);
fileShare.PutFile(folderName, blobName, bytes);

我不太确定 xml.Value (XElement.Value) 是否真的是 GetBytes 方法真正需要的。这是正确的吗?

为了测试这一点,我启动了一个控制台应用程序并输入了一些虚假数据。我为 XElement 做了这个:

XElement root = new XElement("Root",
            new XElement("Child1", 1),
            new XElement("Child2", 2),
            new XElement("Child3", 3),
            new XElement("Child4", 4),
            new XElement("Child5", 5),
            new XElement("Child6", 6)
        );

然后我尝试将那行代码放入字节数组

byte[] bytes = Encoding.Default.GetBytes(root.Value);

好吧,我想我忘记了,当我走过去看到 Autos 时,字节变量是 btye[6],当我展开时 - 我看到 [0] = 49 等等

现在这可能并不意味着它不起作用......或者它是否意味着?如何解读bytes数组的内容,检查是否正确?

【问题讨论】:

  • 这个问题你可以自己回答...xml.Value中的字符串是你要发送的信息吗?
  • 嗯 - XElement 的 Value 的定义是一个包含它所有文本的字符串。我真的知道 XElement 会将属性正确写入 Azure - 我不知道,因为我以前从未使用过它。它深入到目前无法测试的工作流程中 - 所以除非 SO 上的人知道,否则我需要使用控制台应用程序来解决这个问题
  • 不幸的是这个问题已经变成了。 “我需要做点什么,但我需要知道它是否有效。” 你需要更明确一点。您到底想从 XML 元素中得到什么,您需要确保通过网络发送什么。您实际调用的是什么 azure 方法,您希望该调用的结果是什么。此外,如果您不能自己为此编写一个小测试,那么您似乎遇到了更大的问题。如果你能弄清楚其中的一些点,我相信有人可以帮助你
  • @TheGeneral 我创建了一个控制台应用程序,并在我的问题底部放置了一个更新。再次感谢

标签: c# arrays xml character-encoding xelement


【解决方案1】:

首先,不推荐使用Encoding.Default。来自docs

警告

不同的计算机可以使用不同的编码作为默认编码,并且默认编码可以在单台计算机上改变。如果您使用默认编码对计算机之间流式传输的数据进行编码和解码,或者在同一台计算机上的不同时间检索数据,则可能会错误地转换该数据。此外,默认属性返回的编码使用最佳匹配回退将不受支持的字符映射到代码页支持的字符。由于这些原因,不建议使用默认编码。为确保正确解码编码字节,应使用 Unicode 编码,例如 UTF8EncodingUnicodeEncoding。您还可以使用更高级别的协议来确保编码和解码使用相同的格式。

其次XElement.Value返回

包含此元素的所有文本内容的字符串。如果有多个文本节点,它们将被连接起来。

因此,如果您上传Value,您将从文件中剥离整个 XML 标记结构,只留下纯文本。虽然您可能想要这样做,但这似乎不太可能。如果将该值与XElement.ToString() 返回的字符串进行比较,差异应该很明显。

改为,要将您的XElement(包括标记和文本)的XML 内容转换为字节数组,最好将write 您的XElement 直接转换为@ 987654339@ 使用适当配置的XmlWriterSettings 并返回由此创建的字节数组。以下扩展方法可以完成这项工作:

public static partial class XNodeExtensions
{
    static Encoding DefaultEncoding { get; } = new UTF8Encoding(false); // Disable the BOM because XElement.ToString() does not include it.
    
    public static byte [] ToByteArray(this XNode node, SaveOptions options = default, Encoding encoding = default)
    {
        // Emulate the settings of XElement.ToString() and XDocument.ToString()
        // https://referencesource.microsoft.com/#System.Xml.Linq/System/Xml/Linq/XLinq.cs,2004
        // I omitted the XML declaration because XElement.ToString() omits it, but you might want to include it, depending upon your needs.
        var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = (options & SaveOptions.DisableFormatting) == 0, Encoding = encoding ?? DefaultEncoding };
        if ((options & SaveOptions.OmitDuplicateNamespaces) != 0)
            settings.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
        return node.ToByteArray(settings);
    }
    
    public static byte [] ToByteArray(this XNode node, XmlWriterSettings settings)
    {
        using var ms = new MemoryStream();
        using (var writer = XmlWriter.Create(ms, settings))
            node.WriteTo(writer);
        return ms.ToArray();
    }
}

现在您可以通过以下方式将您的 XElement 格式化为 UTF8 编码的字节数组:

var bytes = root.ToByteArray();

扩展方法有一个额外的好处,如果你真的需要使用 UTF8 以外的编码,不受支持的 Unicode 字符将被转义而不是替换为回退,如this answerXmlDocument with Kanji text content is not encoded correctly to ISO-8859-1 using XmlTextWriter

var bytes = root.ToByteArray(encoding : Encoding.Default);

要检查正确性,您可以检查调试器或控制台应用程序中的字节数组的内容,方法是将其解码为如下字符串:

var resultString = Encoding.UTF8.GetString(bytes);
Console.WriteLine(resultString);

或者使用默认编码:

var resultString = Encoding.Default.GetString(bytes);

您还可以通过 assert 将内容解析回新的 XElement 并使用 XNode.DeepEquals() 检查结果在语义上是否与原始结果相同,从而判断字节数组的内容是否正确:

Assert.IsTrue(
    XNode.DeepEquals(root, 
                     XElement.Load(new StreamReader(new MemoryStream(bytes), encoding))));

演示小提琴here.

【讨论】:

    猜你喜欢
    • 2023-01-17
    • 1970-01-01
    • 2013-05-01
    • 2010-09-15
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    相关资源
    最近更新 更多