J'ai un champ VARCHAR(MAX)
qui est interfacé avec un système externe au format XML
. Les erreurs suivantes ont été générées par l'interface:
mywebsite.com-2015-0202.xml:413005: parser error : xmlParseCharRef: invalid xmlChar value 29
ne and Luke's family in Santa Fe. You know you have a standing invitation,
^
mywebsite.com-2015-0202.xml:455971: parser error : xmlParseCharRef: invalid xmlChar value 25
The apprentice nodded, because frankly, who hadnt? That diseases like chol
^
mywebsite.com.com-2015-0202.xml:456077: parser error : xmlParseCharRef: invalid xmlChar value 28
bon mot; a sentimental love of nature and animals; the proverbial British 
^
mywebsite.com-2015-0202.xml:472073: parser error : xmlParseCharRef: invalid xmlChar value 20
"Andyou want that?"
^
mywebsite.com-2015-0202.xml:492912: parser error : xmlParseCharRef: invalid xmlChar value 25
She couldnt live like this anymore.
Nous avons constaté que la liste de caractères suivante n'est pas valide:
�








	
























J'essaie de nettoyer ces données et j'ai trouvé une fonction SQL pour nettoyer ces caractères ici . Cependant, la fonction prenait NVARCHAR(4000)
en tant que paramètre d'entrée, j'ai donc modifié la fonction pour utiliser VARCHAR(MAX)
à la place.
Est-ce que quelqu'un pourrait nous dire si changer le NVARCHAR(4000)
en VARCHAR(MAX)
produirait des résultats erronés? Désolé, je ne serais pas en mesure de tester cette interface localement alors j'ai pensé demander l'avis/le conseil.
Fonction d'origine:
CREATE FUNCTION fnStripLowAscii (@InputString nvarchar(4000))
RETURNS nvarchar(4000)
AS
BEGIN
IF @InputString IS NOT NULL
BEGIN
DECLARE @Counter int, @TestString nvarchar(40)
SET @TestString = '%[' + NCHAR(0) + NCHAR(1) + NCHAR(2) + NCHAR(3) + NCHAR(4) + NCHAR(5) + NCHAR(6) + NCHAR(7) + NCHAR(8) + NCHAR(11) + NCHAR(12) + NCHAR(14) + NCHAR(15) + NCHAR(16) + NCHAR(17) + NCHAR(18) + NCHAR(19) + NCHAR(20) + NCHAR(21) + NCHAR(22) + NCHAR(23) + NCHAR(24) + NCHAR(25) + NCHAR(26) + NCHAR(27) + NCHAR(28) + NCHAR(29) + NCHAR(30) + NCHAR(31) + ']%'
SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)
WHILE @Counter <> 0
BEGIN
SELECT @InputString = STUFF(@InputString, @Counter, 1, NCHAR(164))
SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)
END
END
RETURN(@InputString)
END
Version modifiée:
CREATE FUNCTION [dbo].RemoveInvalidXMLCharacters (@InputString VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
IF @InputString IS NOT NULL
BEGIN
DECLARE @Counter INT, @TestString NVARCHAR(40)
SET @TestString = '%[' + NCHAR(0) + NCHAR(1) + NCHAR(2) + NCHAR(3) + NCHAR(4) + NCHAR(5) + NCHAR(6) + NCHAR(7) + NCHAR(8) + NCHAR(11) + NCHAR(12) + NCHAR(14) + NCHAR(15) + NCHAR(16) + NCHAR(17) + NCHAR(18) + NCHAR(19) + NCHAR(20) + NCHAR(21) + NCHAR(22) + NCHAR(23) + NCHAR(24) + NCHAR(25) + NCHAR(26) + NCHAR(27) + NCHAR(28) + NCHAR(29) + NCHAR(30) + NCHAR(31) + ']%'
SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)
WHILE @Counter <> 0
BEGIN
SELECT @InputString = STUFF(@InputString, @Counter, 1, ' ')
SELECT @Counter = PATINDEX (@TestString, @InputString COLLATE Latin1_General_BIN)
END
END
RETURN(@InputString)
END
VARCHAR(MAX)
est sûr car ma colonne de données est un champ VARCHAR(MAX)
. En outre, la conversion de VARCHAR(MAX)
en NVARCHAR(MAX)
si je transmets un champ VARCHAR(MAX)
à la fonction SQL, qui accepte le paramètre NVARCHAR(MAX)
, entraînera une surcharge.
Merci beaucoup @RhysJones, @Damien_The_Unbeliever pour vos commentaires.
Il existe une astuce utilisant la conversion implicite de VARBINARY
en base64 et inversement:
Ici votre liste du mal
DECLARE @evilChars VARCHAR(MAX)=
CHAR(0x0)
+ CHAR(0x1)
+ CHAR(0x2)
+ CHAR(0x3)
+ CHAR(0x4)
+ CHAR(0x5)
+ CHAR(0x6)
+ CHAR(0x7)
+ CHAR(0x8)
+ CHAR(0x9)
+ CHAR(0xa)
+ CHAR(0xb)
+ CHAR(0xc)
+ CHAR(0xd)
+ CHAR(0xe)
+ CHAR(0xf)
+ CHAR(0x10)
+ CHAR(0x11)
+ CHAR(0x12)
+ CHAR(0x13)
+ CHAR(0x14)
+ CHAR(0x15)
+ CHAR(0x16)
+ CHAR(0x17)
+ CHAR(0x18)
+ CHAR(0x19)
+ CHAR(0x1a)
+ CHAR(0x1b)
+ CHAR(0x1c)
+ CHAR(0x1d)
+ CHAR(0x1e)
+ CHAR(0x1f)
+ CHAR(0x7f);
Cela marche
DECLARE @XmlAsString NVARCHAR(MAX)=
(
SELECT @evilChars FOR XML PATH('test')
);
SELECT @XmlAsString;
Le résultat (certains sont "imprimés")
<test>�

</test>
Ce qui suit est interdit
SELECT CAST(@XmlAsString AS XML)
Mais vous pouvez utiliser la conversion implicite de VARBINARY en base64
DECLARE @base64 NVARCHAR(MAX)=
(
SELECT CAST(@evilChars AS VARBINARY(MAX)) FOR XML PATH('test')
);
SELECT @base64;
Le résultat
<test>AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh9/</test>
Vous avez maintenant votre vrai XML, y compris les caractères spéciaux !
SELECT CAST(CAST(@base64 AS XML).value('/test[1]','varbinary(max)') AS VARCHAR(MAX)) FOR XML PATH('reconverted')
Vous devez utiliser nvarchar(max)
au lieu de varchar(max)
, mais sinon, le changement est correct.