كيف يمكنك إزالة باطل حرفا سداسي عشري من XML القائمة على البيانات المصدر قبل بناء XmlReader أو XPathDocument التي تستخدم البيانات ؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

هل هناك أي سهلة/طريقة لتنظيف XML القائمة على البيانات المصدر قبل استخدامه في XmlReader حتى أستطيع أن برشاقة تستهلك بيانات XML غير conformant إلى عشري حرف القيود المفروضة على XML ؟

ملاحظة:

  • الحل يحتاج إلى التعامل مع XML مصادر البيانات التي تستخدم الحرف ترميزات أخرى من UTF-8, على سبيل المثالقبل تحديد ترميز الأحرف في مستند XML الإعلان.لا تغيير اسم ترميز الأحرف من المصدر حين تجريد صالح حرفا سداسي عشري تم نقطة خلاف رئيسية.
  • إزالة غير صالحة حرفا سداسي عشري يجب فقط إزالة الست عشري ترميز القيم ، كما يمكنك غالبا ما تجد href القيم في البيانات التي يحدث يحتوي على سلسلة من شأنها أن تكون سلسلة تطابق عشري حرف.

الخلفية:

أنا بحاجة إلى تستهلك XML القائمة على مصدر البيانات الذي يتوافق مع صيغة محددة (اعتقد ذرة أو آر إس إس) ، ولكن تريد أن تكون قادرة على استهلاك مصادر البيانات التي تم نشرها والتي تحتوي على باطل حرفا سداسي عشري في مواصفات XML.

في .صافي إذا كان لديك تيار يمثل مصدر البيانات XML ثم محاولة تحليل ذلك باستخدام XmlReader و/أو XPathDocument, يتم رفع استثناء بسبب إدراج صالح حرفا سداسي عشري في بيانات XML.بلدي الحالي محاولة لحل هذه المشكلة هو تحليل تيار كسلسلة و استخدام تعبير عادي إزالة و/أو استبدال صالح حرفا سداسي عشري, ولكن أنا أبحث عن المزيد من performant الحل.

هل كانت مفيدة؟

المحلول

ذلك قد لا تكون مثالية (التشديد مضاف لأن الناس في عداد المفقودين هذا تنويه) ، ولكن ما قمت به في هذه الحالة هو أدناه.يمكنك ضبط للاستخدام مع تيار.

/// <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();

}

نصائح أخرى

احب يوجين البيضاء المفهوم.كنت بحاجة إلى فعل شيء مماثل مثل الملصق الأصلي, ولكن أنا في حاجة إلى دعم جميع أحرف Unicode ، ليس فقط ما يصل إلى 0x00FD.XML المواصفات هي:

Char = #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

في .صافي الداخلية تمثيل أحرف Unicode فقط 16 بت, لذلك نحن لا يمكن أن `السماح' 0x10000-0x10FFFF صراحة.XML المواصفات صراحة يسمح البديلة رمز نقطة الانطلاق في 0xD800 من الظهور.ومع ذلك فمن الممكن أنه إذا سمحنا هذه بديلة نقاط الرمز في القائمة البيضاء ، utf-8 ترميز سلسلة لدينا قد تنتج صالح XML في النهاية طالما السليم ترميز utf-8 تم إنتاجها من بديل أزواج utf-16 حرفا في .صافي السلسلة.أنا لم تستكشف هذا على الرغم من ذلك ذهبت مع الرهان الأكثر أمانا و لم تسمح بدلاء في القائمة البيضاء.

التعليقات في يوجين حل مضللة على الرغم من المشكلة هو أن الشخصيات نحن باستثناء غير صالحة XML ...فهي صالحة تماما رمز Unicode نقطة.نحن لا إزالة `غير utf-8 أحرف'.نحن إزالة utf-8 أحرف التي قد لا تظهر بشكل جيد مستندات XML.

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();
}

مثل طريقة لإزالة XML غير صالح الشخصيات أقترح عليك استخدام XmlConvert.IsXmlChar الأسلوب.وأضيف منذ ذلك الحين .NET Framework 4 و يرد في سيلفرلايت أيضا.هنا هو عينة صغيرة:

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;
    }
}

الجافة تنفيذ هذا الجواب'حل (باستخدام منشئ مختلفة - لا تتردد في استخدام كل واحد في التطبيق الخاص بك):

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;
    }
}

تحديث dnewcombe هو الإجابة يمكنك أن تأخذ أبسط قليلا النهج

public static string RemoveInvalidXmlChars(string input)
{
    var isValid = new Predicate<char>(value =>
        (value >= 0x0020 && value <= 0xD7FF) ||
        (value >= 0xE000 && value <= 0xFFFD) ||
        value == 0x0009 ||
        value == 0x000A ||
        value == 0x000D);

    return new string(Array.FindAll(input.ToCharArray(), isValid));
}

أو مع Linq

public static string RemoveInvalidXmlChars(string input)
{
    return new string(input.Where(value =>
        (value >= 0x0020 && value <= 0xD7FF) ||
        (value >= 0xE000 && value <= 0xFFFD) ||
        value == 0x0009 ||
        value == 0x000A ||
        value == 0x000D).ToArray());
}

سأكون مهتما لمعرفة كيفية أداء هذه الأساليب يقارن وكيف أنهم جميعا مقارنة قائمة سوداء النهج باستخدام Buffer.BlockCopy.

هنا dnewcome's الإجابة في العرف StreamReader.ببساطة التفاف حقيقي تيار القارئ يستبدل الأحرف كما هي قراءة.

أنا فقط تنفيذ عدد قليل من الطرق أن أوفر على نفسي الوقت.أنا استخدم هذا بالتزامن مع XDocument.تحميل ملف البث فقط قراءة(char[] العازلة ، الباحث مؤشر عد الباحث) طريقة كانت تسمى ، لذلك عملت مثل هذا.قد تحتاج إلى تنفيذ طرق إضافية للحصول على هذا العمل للتطبيق الخاص بك.أنا استخدم هذا النهج لأنه يبدو أكثر كفاءة من إجابات أخرى.أنا أيضا الوحيدة التي نفذت واحدة من المنشئات ، يمكن تنفيذ أي من StreamReader المنشئات التي تحتاج إليها ، لأنه هو مجرد تمرير من خلال.

اخترت استبدال الأحرف بدلا من إزالتها لأنه يبسط إلى حد كبير حل.في هذه الطريقة طول النص يبقى على حاله ، لذلك ليس هناك حاجة لتتبع مؤشر منفصلة.

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 نهج

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, "");

}

انظر بلدي blogpost لمزيد من التفاصيل

الحلول المذكورة أعلاه يبدو أن إزالة الأحرف غير الصالحة قبل تحويل XML.

استخدام هذا الرمز إلى إزالة XML غير صالح الأحرف من سلسلة XML.على سبيل المثال.&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/

تعديل الإجابة أو الرد الأصلي قبل Neolisk أعلاه.
التغييرات:من \0 شخصية مرت إزالة القيام به بدلا من الاستبدال.أيضا, استخدام XmlConvert.IsXmlChar(شار) طريقة

    /// <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);
        }
    }

استخدام هذه الوظيفة لإزالة xml غير صالح الشخصيات.

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

أنا خلقت قليلا تحديث النسخة من @Neolisk الجواب, التي تدعم *Async وظائف يستخدم .Net 4.0 XmlConvert.IsXmlChar وظيفة.

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 );
}

يمكنك تمرير غير UTF الشخصيات التالية:

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+";";
    }
}

جرب هذا لمدة PHP!

$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top