ISO-8859-1编码导致XML导入后产品描述乱码的技术问题
ISO-8859-1 XML导入乱码问题及解决
问题现象
导入ISO-8859-1编码的XML时,系统分XML验证(展示未注册/已存在产品列表)和实际导入关联两个阶段。XML中的产品描述:
"GPM 25 / VALVULA GPMBRASIL PN 16 COMERCIAL 45º 2.1/2 11 BSP X 5 FPP LATAO C/ VOLANTE Ø 90 MM VERMELHO"
插入系统后变为:
"GPM 25 / VALVULA GPMBRASIL PN 16 COMERCIAL 45º 2.1/2 11 BSP X 5 FPP LATAO C/ VOLANTE � 90 MM VERMELHO"
特殊字符乱码导致后续产品匹配无法找到已注册产品。
现有代码
控制器读取XML代码
XDocument xdoc = null; using (StreamReader oReader = new StreamReader(file.InputStream, Encoding.GetEncoding("ISO-8859-1"))) { xdoc = XDocument.Load(oReader); } using (var xmlReader = xdoc.CreateReader()) { importacao.XmlDocument.Load(xmlReader); }
生成产品列表方法代码
var produtosDoXML = nodeProdutos.Cast<XmlNode>().Select(x => new { Codigo = x["prod"]["cProd"].InnerText, Descricao = x["prod"]["xProd"].InnerText, NCM = x["prod"]["NCM"]?.InnerText, CEST = x["prod"]["CEST"]?.InnerText, EANTributavel = x["prod"]["cEANTrib"]?.InnerText, EAN = x["prod"]["cEAN"]?.InnerText, UnidadeComercial = x["prod"]["uCom"]?.InnerText, Quantidade = Convert.ToDecimal(x["prod"]["qCom"].InnerText, CultureInfo.InvariantCulture), Desconto = Convert.ToDecimal(x["prod"]["vDesc"]?.InnerText, CultureInfo.InvariantCulture), ValorUnitario = Math.Round(Convert.ToDecimal(x["prod"]["vUnCom"]?.InnerText, CultureInfo.InvariantCulture), 4), OrdemDeExibicao = int.Parse(x.Attributes["nItem"].Value) }); foreach (var produtoDoXML in produtosDoXML) { var produtos = produtosServicosDosFornecedores.Where(x => x.CodigoEquivalente == produtoDoXML.Codigo && x.DescricaoEquivalente == produtoDoXML.Descricao); if (produtos.Count() > 1) { throw new CompraException(CompraException.TypeException.ProdutoEquivalenteDeTerceiroDuplicado, "", produtoDoXML.Codigo); } else if (produtos.Count() == 0) { var produtosAssociadosAoCodigo = produtosServicosDosFornecedores.Where(x => x.CodigoEquivalente == produtoDoXML.Codigo) .GroupBy(x => x.ProdutoServicoId); if (produtosAssociadosAoCodigo.Count() == 1) { retornoDaImportacao.AdicionarProdutoNaoAssociadoComCodigoExistente(new RetornoImportacaoXMLDeNFeDeCompraDTO.ProdutoNaoAssociadoComCodigoExistente { IdDoProdutoAssociado = produtosAssociadosAoCodigo.Single().First().ProdutoServico.Id, CodigoDoProdutoAssociado = produtosAssociadosAoCodigo.Single().First().ProdutoServico.Codigo, DescricaoDoProdutoAssociado = produtosAssociadosAoCodigo.Single().First().ProdutoServico.Descricao, NomeDoFornecedor = fornecedor.NomeFantasia, IdDoFornecedor = fornecedor.Id, Codigo = produtoDoXML.Codigo, Descricao = produtoDoXML.Descricao, EAN = produtoDoXML.EAN, EANTributavel = produtoDoXML.EANTributavel, CEST = produtoDoXML.CEST, NCM = produtoDoXML.NCM, UnidadeComercial = produtoDoXML.UnidadeComercial, Valor = produtoDoXML.ValorUnitario, }); } else { retornoDaImportacao.AdicionarErroDeProdutoServico(new RetornoImportacaoXMLDeNFeDeCompraDTO.ErroDeProdutoServico { Mensagem = string.Format(Language.Exception_ProdutoXNaoEncontrado, $"[{produtoDoXML.Codigo} - {produtoDoXML.Descricao}]"), NomeDoFornecedor = fornecedor.NomeFantasia, IdDoFornecedor = fornecedor.Id, Codigo = produtoDoXML.Codigo, Descricao = produtoDoXML.Descricao, EAN = produtoDoXML.EAN, EANTributavel = produtoDoXML.EANTributavel, CEST = produtoDoXML.CEST, NCM = produtoDoXML.NCM, UnidadeComercial = produtoDoXML.UnidadeComercial, Valor = produtoDoXML.ValorUnitario }); } } else { retornoDaImportacao.AdicionarProdutoAssociado(new RetornoImportacaoXMLDeNFeDeCompraDTO.ProdutoAssociado { IdDoProduto = produtos.First().Id, CodigoDoProdutoAssociado = produtos.First().ProdutoServico.Codigo, DescricaoDoProdutoAssociado = produtos.First().ProdutoServico.Descricao, NomeDoFornecedor = fornecedor.NomeFantasia, IdDoFornecedor = fornecedor.Id, Codigo = produtoDoXML.Codigo, Descricao = produtoDoXML.Descricao, EAN = produtoDoXML.EAN, EANTributavel = produtoDoXML.EANTributavel, CEST = produtoDoXML.CEST, NCM = produtoDoXML.NCM, UnidadeComercial = produtoDoXML.UnidadeComercial, Valor = produtoDoXML.ValorUnitario, }); } }
解决方法
1. 简化XML读取流程,避免XDocument中转
原代码通过XDocument中转后再加载到XmlDocument,两次解析容易引发编码转换错误。直接使用XmlDocument加载指定编码的流:
importacao.XmlDocument = new XmlDocument(); using (StreamReader oReader = new StreamReader(file.InputStream, Encoding.GetEncoding("ISO-8859-1"))) { importacao.XmlDocument.Load(oReader); }
2. 检查数据库存储字段类型
确保存储产品描述的数据库字段为Unicode兼容类型:
- SQL Server:使用
nvarchar/ntext(而非varchar/text) - MySQL:使用
utf8mb4字符集的varchar(而非latin1字符集字段)
非Unicode字段无法正确存储特殊字符,会导致乱码或字符丢失。
3. 验证XML文件编码声明
确认XML文件开头的编码声明与实际文件编码一致:
<?xml version="1.0" encoding="ISO-8859-1"?>
若声明编码与实际编码不符,解析时会自动按声明编码处理,导致乱码。
内容的提问来源于stack exchange,提问作者Guilherme Costa
相关产品推荐
相关产品推荐

