You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:32:02