解码来自xml文档的base64编码数据

时间:2009-11-20 15:30:37

标签: c# xml base64 decode

我收到一些带有嵌入式base64编码图像的xml文件,我需要将其解码并保存为文件。

可以在下面下载此类文件的未修改(除了压缩)示例:

20091123-125320.zip(60KB)

但是,我收到诸如“Base-64 char数组的长度无效”和“Base-64字符串中的无效字符”之类的错误。我在代码中标记了代码中的行。

文件可能如下所示:

<?xml version="1.0" encoding="windows-1252"?>
<mediafiles>
    <media media-type="image">
      <media-reference mime-type="image/jpeg"/>
      <media-object encoding="base64"><![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]></media-object>
      <media.caption>What up</media.caption>
    </media>
</mediafiles>

要处理的代码如下:

var xd = new XmlDocument();
xd.Load(filename);
var nodes = xd.GetElementsByTagName("media");

foreach (XmlNode node in nodes)
        {
            var mediaObjectNode = node.SelectSingleNode("media-object");
            //The line below is where the errors occur
            byte[] imageBytes = Convert.FromBase64String(mediaObjectNode.InnerText);
            //Do stuff with the bytearray to save the image
        }

xml-data来自企业报纸系统,所以我很确定文件是正确的 - 我必须有一些处理方式,这是错误的。也许是编码问题?

我试过写出mediaObjectNode.InnerText的内容,它是base64编码的数据 - 所以导航xml-doc不是问题。

我一直在谷歌搜索,binging,stackoverflowing和哭 - 并找不到解决方案......帮助!

编辑:

添加了一个实际的示例文件(以及赏金)。请注意,可下载文件的架构有点不同,因为我在上面的示例中对其进行了简化,删除了不相关的内容......

7 个答案:

答案 0 :(得分:9)

对于第一次拍摄我没有使用任何编程语言,只是Notepad ++

我在其中打开了xml文件,并将原始base64内容复制并粘贴到一个新文件中(没有方括号)。

之后我选择了所有内容(Strg-A)并使用了Extensions选项 - Mime Tools - Base64 decode。这引发了关于错误文本长度的错误(必须是mod 4)。所以我在末尾添加了两个等号('=')作为占位符以获得正确的长度。

另一次重试并成功解码为'某事'。只需将文件另存为.jpg,它就会像任何图片浏览器中的魅力一样打开。

所以我想说,你得到的数据有问题。他们只是在最后没有正确数量的等号来填补一些可以分成4个包的标志。

'简单'的方法是添加等号直到解码不会引发错误。更好的方法是计算字符数(减去CR / LF!)并一步添加所需的字符。

进一步调查

在对the convert function进行一些编码和读取之后,问题是从生产者那里错误地附加了等号。 Notepad ++没有大量等号的问题,但MS的转换功能仅适用于零,一或两个符号。因此,如果您填写已存在的附加等号,您也会收到错误!为了让这个该死的东西工作,你必须切断所有现有的标志,计算需要多少并再次添加它们。

只是为了赏金,这是我的代码(不是绝对完美的,但足以获得一个好的起点):; - )

    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (XElement element in elements)
        {
            var image = AnotherDecode64(element.Value);
        }
    }

    static byte[] AnotherDecode64(string base64Decoded)
    {
        string temp = base64Decoded.TrimEnd('=');
        int asciiChars = temp.Length - temp.Count(c => Char.IsWhiteSpace(c));
        switch (asciiChars % 4)
        {
            case 1:
                //This would always produce an exception!!
                //Regardless what (or what not) you attach to your string!
                //Better would be some kind of throw new Exception()
                return new byte[0];
            case 0:
                asciiChars = 0;
                break;
            case 2:
                asciiChars = 2;
                break;
            case 3:
                asciiChars = 1;
                break;
        }
        temp += new String('=', asciiChars);

        return Convert.FromBase64String(temp);
    }

答案 1 :(得分:1)

如Oliver所说,base64字符串无效,删除空白字符后字符串长度必须是4的倍数。如果你看一下base64字符串的结尾(见下文),你会看到该行比其余的短。

RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

如果删除此行,您的程序将会正常工作,但生成的图像右下角会显示缺失的部分。您需要填充此行,以便整个字符串长度为corect。根据我的计算,如果你有3个字符,它应该可以工作。

RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

答案 2 :(得分:1)

删除最后2个字符,而图片不正确

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes=null;
        bool iscatch=true;
        while(iscatch)
        {
            try 
                {           
         imageBytes = Convert.FromBase64String(base64String);
         iscatch = false;

            }
            catch 
            {
                int length=base64String.Length;
                base64String=base64String.Substring(0,length-2);
            }
        }
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        pictureBox1.Image = image;
        return image;
    }

答案 3 :(得分:0)

尝试使用Linq to XML:

using System.Xml.XPath;

class Program
{
    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (var element in elements)
        {
            byte[] image = Convert.FromBase64String(element.Value);
        }
    }
}

更新:

下载XML文件并分析media-object节点的值后,很明显它不是有效的base64字符串:

string value = "PUT HERE THE BASE64 STRING FROM THE XML WITHOUT THE NEW LINES";
byte[] image = Convert.FromBase64String(value);

抛出System.FormatException表示长度不是有效的64位字符串。当我从字符串中删除\n时它不起作用的事件:

var elements = XElement
    .Load("20091123-125320.xml")
    .XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (var element in elements)
{
    string value = element.Value.Replace("\n", "");
    byte[] image = Convert.FromBase64String(value);
}

也会抛出System.FormatException

答案 4 :(得分:0)

我还遇到了从XML文档(特别是Office OpenXML包文档)解码Base64编码字符串的问题。

事实证明,字符串应用了额外的编码:HTML编码,因此首先进行HTML解码然后进行Base64解码就可以了:

private static byte[] DecodeHtmlBase64String(string value)
{
    return System.Convert.FromBase64String(System.Net.WebUtility.HtmlDecode(value));
}

以防其他人偶然发现同一问题。

答案 5 :(得分:-1)

嗯,这一切都非常简单。 CDATA本身就是一个节点,因此mediaObjectNode.InnerText实际上会生成<![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]>,这显然不是有效的Base64编码数据。

要使工作正常,请使用mediaObjectNode.ChildNodes[0].Value并将该值传递给Convert.FromBase64String'

答案 6 :(得分:-2)

字符编码是否正确?该错误听起来像是一个导致无效字符出现在数组中的问题。尝试复制文本并手动解码以查看数据是否确实有效。

(对于记录,windows-1252与iso-8859-1不完全相同,因此可能是问题的原因,除非有其他腐败来源。)