Hoe kan jy ongeldig heksadesimale karakters verwyder uit 'n XML-gebaseerde data bron voor die bou van 'n XmlReader of XPathDocument dat die data gebruik?

StackOverflow https://stackoverflow.com/questions/20762

  •  09-06-2019
  •  | 
  •  

Vra

Is daar enige maklik / algemene manier om 'n XML-gebaseerde data bron skoon voor gebruik dit in 'n XmlReader sodat ek grasieus XML data kan verteer wat nie-conformant aan die heksadesimale karakter beperkings geplaas op XML?

Let wel:

  • Die oplossing moet XML hanteer databronne wat karakter gebruik behalwe UTF-8, bv enkoderings deur spesifiseer die karakter enkodering by die XML dokument verklaring. nie mangling die karakter enkodering van die bron terwyl stroping ongeldig heksadesimale karakters is 'n groot knelpunt.
  • Die verwydering van ongeldig heksadesimale karakters moet net verwyder heksadesimale geënkodeerde waardes, as jy dikwels vind href waardes in data wat gebeur met bevat 'n string wat 'n string wedstryd vir 'n heksadesimaal karakter sou wees.

Agtergrond:

Ek moet 'n XML-gebaseerde data bron wat voldoen aan 'n spesifieke formaat te vernietig (dink Atom of RSS), maar wil in staat wees om data bronne wat gepubliseer wat ongeldig heksadesimale karakters per die XML spesifikasie bevat verteer.

In NET as jy 'n Stroom wat die XML data bron verteenwoordig, en probeer dan om te ontleed dit met behulp van 'n XmlReader en / of XPathDocument, is 'n uitsondering wat as gevolg van die insluiting van ongeldige heksadesimale karakters in die XML data. My huidige poging om hierdie probleem op te los, is om die stroom te ontleed as 'n string en gebruik 'n gewone uitdrukking te verwyder en / of die ongeldig heksadesimale karakters te vervang, maar ek is op soek na 'n meer performante oplossing.

Was dit nuttig?

Oplossing

Dit kan nie perfek (klem bygevoeg sedert mense ontbreek hierdie disclaimer) wees, maar wat ek gedoen het in so 'n geval is hieronder. Jy kan aanpas om te gebruik met 'n stroom.

/// <summary>
/// Removes control characters and other non-UTF-8 characters
/// </summary>
/// <param name="inString">The string to process</param>
/// <returns>A string with no control characters or entities above 0x00FD</returns>
public static string RemoveTroublesomeCharacters(string inString)
{
    if (inString == null) return null;

    StringBuilder newString = new StringBuilder();
    char ch;

    for (int i = 0; i < inString.Length; i++)
    {

        ch = inString[i];
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        //if ((ch < 0x00FD && ch > 0x001F) || ch == '\t' || ch == '\n' || ch == '\r')
        //if using .NET version prior to 4, use above logic
        if (XmlConvert.IsXmlChar(ch)) //this method is new in .NET 4
        {
            newString.Append(ch);
        }
    }
    return newString.ToString();

}

Ander wenke

Ek hou van witlys konsep Eugene se. Ek nodig het om 'n soortgelyke ding doen as die oorspronklike plakkaat, maar ek nodig het om al Unicode-karakters ondersteun, nie net tot 0x00FD. Die XML spec is:

Char = # x9 | #xA | #xD | [# X20- # xD7FF] | [# XE000- # xFFFD] | [# X10000- # x10FFFF]

In NET, die interne voorstelling van Unicode-karakters is net 16 stukkies, sodat ons kan nie `toelaat '0x10000-0x10FFFF uitdruklik. Die XML spec uitdruklik verbied die surrogaat-kode punte begin by 0xD800 verskyn. Dit is egter moontlik dat as ons toegelaat hierdie surrogaat-kode punte in ons witlys, UTF-8 kodering ons string kan geldig XML te produseer op die ou end so lank as behoorlike utf-8-kodering is afkomstig van die surrogaat pare utf-16 karakters in die NET string. Ek het nie verken hierdie al is, so ek het met die veiliger verbintenis en nie toelaat dat die surrogate in my witlys.

Die kommentaar in oplossing Eugene se al misleidend, die probleem is dat die karakters wat ons uitgesluit is nie geldig in XML ... hulle is volkome geldig Unicode-kode punte. Ons is nie die verwydering van `n nie-utf-8 karakters. Ons is die verwydering van utf-8 karakters wat nie in goed gevormde XML dokumente kan verskyn.

public static string XmlCharacterWhitelist( string in_string ) {
    if( in_string == null ) return null;

    StringBuilder sbOutput = new StringBuilder();
    char ch;

    for( int i = 0; i < in_string.Length; i++ ) {
        ch = in_string[i];
        if( ( ch >= 0x0020 && ch <= 0xD7FF ) || 
            ( ch >= 0xE000 && ch <= 0xFFFD ) ||
            ch == 0x0009 ||
            ch == 0x000A || 
            ch == 0x000D ) {
            sbOutput.Append( ch );
        }
    }
    return sbOutput.ToString();
}

As die pad na ongeldig XML karakters Ek stel voor jy gebruik XmlConvert.IsXmlChar metode. Dit is sedert NET Framework 4 bygevoeg en word aangebied in Silver ook. Hier is die klein monster:

void Main() {
    string content = "\v\f\0";
    Console.WriteLine(IsValidXmlString(content)); // False

    content = RemoveInvalidXmlChars(content);
    Console.WriteLine(IsValidXmlString(content)); // True
}

static string RemoveInvalidXmlChars(string text) {
    char[] validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray();
    return new string(validXmlChars);
}

static bool IsValidXmlString(string text) {
    try {
        XmlConvert.VerifyXmlChars(text);
        return true;
    } catch {
        return false;
    }
}

DRY implementering van oplossing hierdie antwoord se (met behulp van 'n ander konstruktor - voel vry om die een wat jy nodig het in gebruik jou aansoek):

public class InvalidXmlCharacterReplacingStreamReader : StreamReader
{
    private readonly char _replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)
    {
        this._replacementCharacter = replacementCharacter;
    }

    public override int Peek()
    {
        int ch = base.Peek();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return this._replacementCharacter;
        }
        return ch;
    }

    public override int Read()
    {
        int ch = base.Read();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return this._replacementCharacter;
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        int readCount = base.Read(buffer, index, count);
        for (int i = index; i < readCount + index; i++)
        {
            char ch = buffer[i];
            if (IsInvalidChar(ch))
            {
                buffer[i] = this._replacementCharacter;
            }
        }
        return readCount;
    }

    private static bool IsInvalidChar(int ch)
    {
        return (ch < 0x0020 || ch > 0xD7FF) &&
               (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D;
    }
}

Hier is dnewcome se antwoord in 'n persoonlike StreamReader. Dit vou net 'n ware stroom leser en vervang die karakters soos hulle gelees word.

Ek geïmplementeer slegs 'n paar metodes om myself te red tyd. Ek gebruik dit in samewerking met XDocument.Load en 'n lêer stroom en net die Read (char [] buffer, int indeks, int telling) metode genoem word, so dit het gewerk soos hierdie. Dit mag nodig wees om addisionele metodes te implementeer om dit te kry om te werk vir jou aansoek. Ek gebruik hierdie benadering omdat dit meer doeltreffend as die ander antwoorde lyk. Ek het ook net geïmplementeer een van die vervaardigerskampioenskap, jy kan natuurlik implementeer enige van die StreamReader vervaardigerskampioenskap wat jy nodig het, want dit is net 'n pas deur.

Ek het gekies om die karakters eerder vervang as hulle te verwyder omdat dit grootliks die oplossing vergemaklik. Op hierdie wyse die lengte van die teks bly dieselfde, so daar is geen rede om tred te hou van 'n aparte indeks te hou.

public class InvalidXmlCharacterReplacingStreamReader : TextReader
{
    private StreamReader implementingStreamReader;
    private char replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter)
    {
        implementingStreamReader = new StreamReader(stream);
        this.replacementCharacter = replacementCharacter;
    }

    public override void Close()
    {
        implementingStreamReader.Close();
    }

    public override ObjRef CreateObjRef(Type requestedType)
    {
        return implementingStreamReader.CreateObjRef(requestedType);
    }

    public void Dispose()
    {
        implementingStreamReader.Dispose();
    }

    public override bool Equals(object obj)
    {
        return implementingStreamReader.Equals(obj);
    }

    public override int GetHashCode()
    {
        return implementingStreamReader.GetHashCode();
    }

    public override object InitializeLifetimeService()
    {
        return implementingStreamReader.InitializeLifetimeService();
    }

    public override int Peek()
    {
        int ch = implementingStreamReader.Peek();
        if (ch != -1)
        {
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                return replacementCharacter;
            }
        }
        return ch;
    }

    public override int Read()
    {
        int ch = implementingStreamReader.Read();
        if (ch != -1)
        {
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                return replacementCharacter;
            }
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        int readCount = implementingStreamReader.Read(buffer, index, count);
        for (int i = index; i < readCount+index; i++)
        {
            char ch = buffer[i];
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                buffer[i] = replacementCharacter;
            }
        }
        return readCount;
    }

    public override Task<int> ReadAsync(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override int ReadBlock(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override string ReadLine()
    {
        throw new NotImplementedException();
    }

    public override Task<string> ReadLineAsync()
    {
        throw new NotImplementedException();
    }

    public override string ReadToEnd()
    {
        throw new NotImplementedException();
    }

    public override Task<string> ReadToEndAsync()
    {
        throw new NotImplementedException();
    }

    public override string ToString()
    {
        return implementingStreamReader.ToString();
    }
}

Regex benadering

public static string StripInvalidXmlCharacters(string str)
{
    var invalidXmlCharactersRegex = new Regex("[^\u0009\u000a\u000d\u0020-\ud7ff\ue000-\ufffd]|([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])");
    return invalidXmlCharactersRegex.Replace(str, "");

}

Sien my blog post vir meer besonderhede

Die bogenoemde oplossings blyk te wees vir die verwydering van ongeldige karakters voor die omskakeling na XML.

Gebruik hierdie kode om ongeldig XML karakters van 'n XML-string te verwyder. bv. & X1A;

    public static string CleanInvalidXmlChars( string Xml, string XMLVersion )
    {
        string pattern = String.Empty;
        switch( XMLVersion )
        {
            case "1.0":
                pattern = @"&#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F]);";
                break;
            case "1.1":
                pattern = @"&#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF]);";
                break;
            default:
                throw new Exception( "Error: Invalid XML Version!" );
        }

        Regex regex = new Regex( pattern, RegexOptions.IgnoreCase );
        if( regex.IsMatch( Xml ) )
            Xml = regex.Replace( Xml, String.Empty );
        return Xml;
    }

http: / /balajiramesh.wordpress.com/2008/05/30/strip-illegal-xml-characters-based-on-w3c-standard/

Gewysig antwoord of oorspronklike antwoord deur Neolisk bo .
Wysigings: van \ 0 karakter aangeneem word, is die verwydering gedoen, eerder as 'n plaasvervanger. ook, het gebruik gemaak van XmlConvert.IsXmlChar (char) metode

    /// <summary>
    /// Replaces invalid Xml characters from input file, NOTE: if replacement character is \0, then invalid Xml character is removed, instead of 1-for-1 replacement
    /// </summary>
    public class InvalidXmlCharacterReplacingStreamReader : StreamReader
    {
        private readonly char _replacementCharacter;

        public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter)
            : base(fileName)
        {
            _replacementCharacter = replacementCharacter;
        }

        public override int Peek()
        {
            int ch = base.Peek();
            if (ch != -1 && IsInvalidChar(ch))
            {
                if ('\0' == _replacementCharacter)
                    return Peek(); // peek at the next one

                return _replacementCharacter;
            }
            return ch;
        }

        public override int Read()
        {
            int ch = base.Read();
            if (ch != -1 && IsInvalidChar(ch))
            {
                if ('\0' == _replacementCharacter)
                    return Read(); // read next one

                return _replacementCharacter;
            }
            return ch;
        }

        public override int Read(char[] buffer, int index, int count)
        {
            int readCount= 0, ch;

            for (int i = 0; i < count && (ch = Read()) != -1; i++)
            {
                readCount++;
                buffer[index + i] = (char)ch;
            }

            return readCount;
        }


        private static bool IsInvalidChar(int ch)
        {
            return !XmlConvert.IsXmlChar((char)ch);
        }
    }

Gebruik hierdie funksie om ongeldig XML karakters verwyder.

public static string CleanInvalidXmlChars(string text)   
{   
       string re = @"[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD\x10000-x10FFFF]";   
       return Regex.Replace(text, re, "");   
} 

Ek geskep n effens opgedateerde weergawe van @ Neolisk se antwoord , wat die *Async funksies ondersteun en gebruik die Net 4,0 XmlConvert.IsXmlChar funksie.

public class InvalidXmlCharacterReplacingStreamReader : StreamReader
{
    private readonly char _replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)
    {
        _replacementCharacter = replacementCharacter;
    }

    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter) : base(stream)
    {
        _replacementCharacter = replacementCharacter;
    }

    public override int Peek()
    {
        var ch = base.Peek();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return _replacementCharacter;
        }
        return ch;
    }

    public override int Read()
    {
        var ch = base.Read();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return _replacementCharacter;
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        var readCount = base.Read(buffer, index, count);
        ReplaceInBuffer(buffer, index, readCount);
        return readCount;
    }

    public override async Task<int> ReadAsync(char[] buffer, int index, int count)
    {
        var readCount = await base.ReadAsync(buffer, index, count).ConfigureAwait(false);
        ReplaceInBuffer(buffer, index, readCount);
        return readCount;
    }

    private void ReplaceInBuffer(char[] buffer, int index, int readCount)
    {
        for (var i = index; i < readCount + index; i++)
        {
            var ch = buffer[i];
            if (IsInvalidChar(ch))
            {
                buffer[i] = _replacementCharacter;
            }
        }
    }

    private static bool IsInvalidChar(int ch)
    {
        return IsInvalidChar((char)ch);
    }

    private static bool IsInvalidChar(char ch)
    {
        return !XmlConvert.IsXmlChar(ch);
    }
}
private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

Jy kan slaag nie-UTF karakters met die volgende:

string sFinalString  = "";
string hex = "";
foreach (char ch in UTFCHAR)
{
    int tmp = ch;
   if ((ch < 0x00FD && ch > 0x001F) || ch == '\t' || ch == '\n' || ch == '\r')
    {
    sFinalString  += ch;
    }
    else
    {  
      sFinalString  += "&#" + tmp+";";
    }
}

Probeer dit vir PHP!

$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top