繁体   English   中英

如何将 XElement 转换为字节数组以进行 PutFile 操作?

[英]How can I convert an XElement to a byte array for a PutFile operation?

我需要将大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数组的内容,以检查它是否正确?

首先,不推荐使用Encoding.Default 文档

警告

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

其次XElement.Value返回

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

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

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

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 answer to XmlDocument with Kanji text content is not encrypted to ISO -8859-1 使用 XmlTextWriter

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

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

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

或者使用默认编码:

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

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

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

演示小提琴在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM