【问题标题】:Decoding base64-encoded data from xml document从 xml 文档中解码 base64 编码的数据
【发布时间】:2010-12-18 18:42:22
【问题描述】:

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

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

20091123-125320.zip (60KB)

但是,我收到诸如“Base-64 字符数组的长度无效”和“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 不是问题。

我一直在谷歌搜索、搜索、stackoverflow 和哭泣 - 并没有找到解决方案...帮助!

编辑:

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

【问题讨论】:

    标签: c# xml base64 decode


    【解决方案1】:

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

    (作为记录,windows-1252 与 iso-8859-1 并不完全相同,因此这可能是问题的原因,除非其他损坏源。)

    【讨论】:

    • 好吧-也许那里有错误,但这就是我获取文件的方式(使用此编码)。如何检查它是否正确?
    【解决方案2】:

    嗯,这一切都很简单。 CDATA 本身就是一个节点,所以mediaObjectNode.InnerText 实际上会产生&lt;![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]&gt;,这显然不是有效的Base64 编码数据。

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

    【讨论】:

    • 我尝试将 mediaObjectNode.InnerText 的内容保存到 text.file(在将其输出到控制台之后),并且不包含 cdata-stuff。无论如何我尝试了你的建议,但没有任何区别。
    【解决方案3】:

    尝试使用 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 表示长度不是有效的 base 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】:

      第一次拍摄我没有使用任何编程语言,只是记事本++

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

      之后我选择了所有内容 (Strg-A) 并使用了选项扩展 - Mime 工具 - Base64 解码。这引发了关于错误文本长度的错误(必须是 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);
          }
      

      【讨论】:

      • @Oliver,我知道这是一个旧答案,但我一直在努力解决这个问题。原来是因为那里有三个“=”符号。谁知道?谢谢!
      【解决方案5】:

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

      RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=
      

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

      RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=
      

      【讨论】:

        【解决方案6】:

        图像不正确时删除最后 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;
            }
        

        【讨论】:

          【解决方案7】:

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

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

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

          以防万一其他人遇到同样的问题。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-24
            • 2011-11-02
            • 2011-01-31
            相关资源
            最近更新 更多