AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 278684
Accepted
McNets
McNets
Asked: 2020-10-27 05:57:03 +0800 CST2020-10-27 05:57:03 +0800 CST 2020-10-27 05:57:03 +0800 CST

Erro ao converter VARCHAR(MAX) para XML devido ao atributo "UTF-8"

  • 772

Eu preciso cavar em uma tabela de logs com um esquema semelhante a este:

CREATE TABLE t (
  id int PRIMARY KEY,
  data varchar(max)
);

A coluna dataarmazena um texto XML recebido de um serviço da web neste formato:

Esta é uma versão reduzida

<?xml version="1.0" encoding="UTF-8"?>
<PARAM>
  <TAB DIM="30" ID="ZC3D2_1" SIZE="5">
    <LIN NUM = "1">
      <FLD NAME = "ZDOC" TYPE = "Char">Ferran López</FLD>
    </LIN>
  </TAB>
</PARAM>

Quando tento converter este texto para XML, recebo o próximo erro:

Análise XML: linha xx, caractere 48, caractere xml ilegal

Isso pode ser resolvido removendo a <xml>tag, ou pelo menos, o encodingatributo.

NOTA: Funciona bem se não houver caracteres especiais como ó, mesmo se eu não remover a <xml>tag.

Pergunta

Existe uma maneira de convertê-lo em XML sem substituir ou remover a <xml>tag?

CAST(REPLACE(data, 'encoding="UTF-8"', '') as XML)

db<>fique aqui

ATUALIZAR

O agrupamento do servidor é: Latin1_General_BIN

Mas mesmo se eu tentar alterar o agrupamento para o agrupamento usual de servidores, ele não funcionará.

SELECT
  id, 
  CAST((data COLLATE Latin1_General_CI_AS) as XML)
FROM
  t;
sql-server sql-server-2014
  • 4 4 respostas
  • 5315 Views

4 respostas

  • Voted
  1. Mikael Eriksson
    2020-10-27T13:56:33+08:002020-10-27T13:56:33+08:00

    Seu XML armazenado em uma coluna varchar(max) deve ficar assim.

    <?xml version="1.0" encoding="UTF-8"?>
    <PARAM>
      <TAB DIM="30" ID="ZC3D2_1" SIZE="5">
        <LIN NUM = "1">
          <FLD NAME = "ZDOC" TYPE = "Char">Ferran López</FLD>
        </LIN>
      </TAB>
    </PARAM>
    

    O ódeve ser representado com um valor de byte duplo ó.

    Se você não tiver uma string codificada em UTF-8 armazenada em sua coluna, a maneira correta de fazer isso é remover a codificação do XML antes de converter o valor para o tipo de dados XML.

    • 7
  2. Tibor Karaszi
    2020-10-27T07:12:58+08:002020-10-27T07:12:58+08:00

    Acho que você tem um problema mais profundo. O UTF-8 permite mais caracteres do que os agrupamentos não Unicode regulares no SQL Server. Portanto, para estar seguro, você deve usar o SQL Server 2019, que possui agrupamentos UTF-8 (e eu entendo se isso não for viável / desejável por muitos motivos) ou use (tente) nvarchar em vez de varchar.

    Se você tem medo do aumento de armazenamento indo de varchar para nvarchar, você pode usar a compactação de linha. Mas isso requer Enterprise Edition anterior ao SQL Server 2016.

    • 6
  3. Best Answer
    Solomon Rutzky
    2020-10-28T22:14:20+08:002020-10-28T22:14:20+08:00

    O que está acontecendo aqui é:

    1. O XMLtipo armazena dados internamente como UTF-16 Little Endian (na maioria das vezes, pelo menos). Não importa qual seja a codificação de origem, o resultado final será UTF-16 LE (e sem <xml>tag, portanto, nãoencoding="..." ).
    2. Ao converter uma string para XML:
      1. São os bytes da string que são convertidos, não os caracteres (explicaremos a diferença em um momento)
      2. NVARCHARos dados são assumidos como UTF-16 LE. Se houver uma <xml>tag e ela contiver o encodingatributo, o único valor válido será"UTF-16" .
      3. VARCHARos dados são considerados na página de código de 8 bits associada ao agrupamento dos dados quando não há <xml>tag, ou se existe, mas não há encodingatributo. Caso contrário, os dados serão interpretados como codificados na página de código especificada no encodingatributo (mesmo que estejam codificados na página de código associada ao agrupamento dos dados).
    3. Seus dados provavelmente estão codificados como página de código 1252 do Windows (isso é determinado pelo agrupamento da coluna em que os dados residem, não pelo agrupamento da instância ou mesmo do banco de dados, mas como você menciona que a instância está usando Latin1_General_BIN, é seguro -suficiente para assumir no momento que a coluna está usando o mesmo agrupamento).
    4. O ponto de código para o ócaractere na página de código Windows-1252 é: 0xF3 .
    5. A <xml>tag, no entanto, está declarando que os dados XML estão codificados como UTF-8.
    6. Em UTF-8, 0xF3 deve ser seguido por três bytes, cada um entre 0x80 e 0xBF , mas em seus dados é seguido por um p, que tem um valor de 0x70 . Portanto, você obtém o erro "caractere xml ilegal" (porque encoding="UTF-8"informa à função de conversão que os bytes são bytes UTF-8 válidos; a conversão não vê o ócaractere).

    Suas opções são:

    1. Idealmente, a coluna seria convertida XML e o encodingatributo da <xml>tag, ou a tag inteira <xml>, seria removida no caminho. E, o tipo de XMLdados pode economizar espaço se houver nomes de elemento e/ou atributo repetidos, pois cria uma dicionário (lista de pesquisa) de nomes internamente e registra a estrutura usando os valores de ID.

    2. Defina a [data]coluna para usar um agrupamento UTF-8 (novo no SQL Server 2019, portanto, não é uma opção para você)

    3. Defina a [data]coluna como eNVARCHAR remova o atributo da tag ou a tag inteira .encoding<xml><xml>

    4. Converta a string de entrada em bytes UTF-8. Portanto, o ócaractere é de dois bytes em UTF-8: 0xC3B3 , que aparece como óno Windows-1252.

      DECLARE @Good VARCHAR(MAX) = '<?xml version="1.0" encoding="UTF-8"?><a>hell'
              + CONVERT(VARCHAR(MAX), 0xC3B3)
              + '</a>';
      SELECT @Good, CONVERT(XML, @Good)
      -- <?xml version="1.0" encoding="UTF-8"?><a>helló</a>
      --
      -- <a>helló</a>
      

    NOTAS:

    • Simplesmente remover o encodingatributo da tag, ou a tag <xml>inteira , não é uma opção. Claro, ele funcionará neste caso específico, mas não funcionará em todos os casos devido à coluna e aos agrupamentos UTF-8 não estarem disponíveis no SQL Server 2014. Portanto, quaisquer caracteres Unicode não disponíveis na página de código 1252 do Windows ser convertido para ou (dependendo do caractere BMP ou do caractere suplementar): <xml>VARCHAR ???
      DECLARE @Test VARCHAR(MAX) = '<test>ó - ☢ - ?</test>';
      SELECT @Test, CONVERT(XML, @Test);
      -- <test>ó - ? - ??</test>
      --
      -- <test>ó - ? - ??</test>
      
    • NÃO _ simplesmente o agrupamento da coluna para uma localidade/cultura diferente. Embora isso possa se livrar do erro, só conseguiria isso eliminando silenciosamente os dados que estavam causando o erro. Por exemplo:
      DECLARE @Data NVARCHAR(MAX) = N'ó';
      SELECT CONVERT(VARCHAR(MAX), @Data COLLATE Latin1_General_BIN) AS [Latin1_General],
          CONVERT(VARCHAR(MAX), @Data COLLATE Latin1_General_BIN) COLLATE
                   Cyrillic_General_CI_AS AS [Cyrillic];
      /*
      Latin1_General    Cyrillic
      ó                 o
      */
      
      "Cirílico" usa uma página de código diferente de "Latin1_General" e o ócaractere não está disponível na página de código cirílico. Mas, há um mapeamento "Best Fit" e é por isso que acabamos com um oem vez de um ?.
    • Você e qualquer pessoa que esteja trabalhando no SQL Server 2008 ou mais recente, realmente deveria estar usando os _100_agrupamentos de nível. Além disso, qualquer pessoa que esteja trabalhando no SQL Server 2012 ou mais recente deve, idealmente, usar a _100_ordenação de nível que termina com _SC(para caracteres suplementares). Finalmente, ao precisar de um agrupamento binário no SQL Server 2005 ou mais recente, use um que termine em _BIN2(veja meu post aqui sobre o motivo).
    • Esse problema não tem nada a ver com o fato de a consulta ser ad hoc ou em um procedimento armazenado (T-SQL ou SQLCLR).
    • 5
  4. nbk
    2020-10-27T06:20:56+08:002020-10-27T06:20:56+08:00

    use um agrupamento compatível para seu varchar

    CREATE TABLE t (
      id int PRIMARY KEY,
      data varchar(max) COLLATE Latin1_General_100_CI_AI_SC_UTF8
    );
    
    INSERT INTO t VALUES
    (1, N'<?xml version="1.0" encoding="UTF-8"?>
    <PARAM>
      <TAB DIM="30" ID="ZC3D2_1" SIZE="5">
        <LIN NUM = "1">
          <FLD NAME = "ZDOC" TYPE = "Char">Ferran López</FLD>
        </LIN>
      </TAB>
    </PARAM>
    ')
    GO
    
    SELECT
      id, 
      CAST(data as XML)
    FROM
      t;
    GO
    
    identificação | (Sem nome de coluna)                                                                                                            
    -: | :------------------------------------------------- -------------------------------------------------- ------------------------
     1 | <PARAM><TAB DIM="30" ID="ZC3D2_1" SIZE="5"><LIN NUM="1"><FLD NAME="ZDOC" TYPE="Char">Ferran López</FLD></ LIN></TAB></PARAM>
    

    db<>fique aqui

    • 4

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve