C #에서 잘못된 XML 문자 이스케이프


84

잘못된 XML 문자가 포함 된 문자열이 있습니다. 문자열을 구문 분석하기 전에 잘못된 XML 문자를 어떻게 이스케이프 (또는 제거) 할 수 있습니까?


2
더 많은 컨텍스트를 제공 할 수 있습니까? 샘플 입력 및 샘플 예상 출력. 또한 출력으로 무엇을 하시겠습니까?
Darin Dimitrov 2011

5
XML을 작성하고 있습니까? 아니면 실제로 XML이 아닌 XML을 읽으려고합니까?
Marc Gravell

3
XmlWriter를 사용하면 잘못된 문자를 이스케이프 처리 할 수 ​​있습니다.
Thomas Levesque

2
@alireza 댓글에서 사람들이 묻는 질문 (자세한 내용)에 답하면 더 유용한 답변을 얻을 수 있습니다 ...
Marc Gravell

죄송 해요. 나는 몇 시간 동안 자리를 비 웠습니다. 이 질문으로 이어진 질문을 읽어보세요 : stackoverflow.com/questions/8330619/… 필요한 모든 정보를 얻을 수 있습니다
Alireza Noori

답변:


113

잘못된 XML 문자를 제거하는 방법으로 XmlConvert.IsXmlChar 메서드 를 사용하는 것이 좋습니다 . .NET Framework 4 이후에 추가되었으며 Silverlight에서도 제공됩니다. 다음은 작은 샘플입니다.

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

유효하지 않은 XML 문자를 이스케이프하는 방법으로 XmlConvert.EncodeName 메서드 를 사용하는 것이 좋습니다 . 다음은 작은 샘플입니다.

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

    string encoded = XmlConvert.EncodeName(content);
    Console.WriteLine(IsValidXmlString(encoded)); // True

    string decoded = XmlConvert.DecodeName(encoded);
    Console.WriteLine(content == decoded); // True
}

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

업데이트 : 인코딩 작업이 소스 문자열의 길이보다 크거나 같은 길이의 문자열을 생성한다는 점을 언급해야합니다. 길이 제한이있는 문자열 열의 데이터베이스에 인코딩 된 문자열을 저장하고 데이터 열 제한에 맞게 앱에서 소스 문자열 길이의 유효성을 검사 할 때 중요 할 수 있습니다.


XmlConvert.VerifyXmlChars인수에 잘못된 문자가 포함 된 경우 예외를 throw하지 않고 null 문자열을 반환하고 포함 된 모든 문자가 유효한 경우 인수를 반환합니다. 시도해보십시오 return XmlConvert.VerifyXmlChars (text) != null.
Matt Enright 2013 년


3
트윗 담아 가기 반환 값 문서는 나를 잡아 주셔서 감사합니다.
Matt Enright

3
문자열이 XML 값을 의미하는 경우 XmlConvert.EncodeName을 사용하지 않도록주의하십시오. XML 이름 제한은 XML 값 제한보다 더 엄격하며 이름 인코딩으로 인해 불필요한 예상치 못한 이스케이프가 발생합니다.
David Burg

1
@arik 내 코드는 변환 전후의 XML 문자열 상태를 보여주는 목적만을 보여줍니다. 분명히 코드에서 유효성을 검사 할 필요가 없습니다.
Igor Kustov

67

SecurityElement.Escape 사용

using System;
using System.Security;

class Sample {
  static void Main() {
    string text = "Escape characters : < > & \" \'";
    string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : &lt; &gt; &amp; &quot; &apos;
    Console.WriteLine(xmlText);
  }
}

11
이것은 제어 문자 (예 : char 30)를 이스케이프하지 않습니다.
zimdanen 2013

19

xml을 작성하는 경우 프레임 워크에서 제공하는 클래스를 사용하여 xml을 만듭니다. 탈출이나 그 어떤 것도 신경 쓰지 않아도됩니다.

Console.Write(new XElement("Data", "< > &"));

출력됩니다

<Data>&lt; &gt; &amp;</Data>

형식이 잘못된 XML 파일을 읽어야하는 경우 정규식을 사용 하지 마십시오 . 대신 Html Agility Pack을 사용하십시오 .


좋은. XmlElement를 사용하는 사람을위한 동등한 방법이 있습니까?
djdanlib 2011

3
업데이트 : XmlElement의 InnerText 속성을 설정하면 올바르게 이스케이프되는 것처럼 보입니다. 내 질문에 대답 했어, 후자!
djdanlib 2011

그래서 귀하의 XML이 잘못 형성 되었습니까? 처럼 <Data>&</Data>?
Pierre-Alain Vigeant

2
예, 그게 바로 문제입니다.
Alireza Noori

2
요소의 콘텐츠에 백 스페이스 (0x08), 다른 많은 제어 문자 또는 대리 코드 포인트와 같은 잘못된 문자가 포함되어 있으면 여전히 문제가 발생할 수 있습니다.
jakubiszon 2014 년

6

Irishman에서 제공하는 RemoveInvalidXmlChars 메서드는 대리 문자를 지원하지 않습니다. 테스트하려면 다음 예제를 사용하십시오.

static void Main()
{
    const string content = "\v\U00010330";

    string newContent = RemoveInvalidXmlChars(content);

    Console.WriteLine(newContent);
}

이것은 빈 문자열을 반환하지만 안됩니다! U + 10330 문자는 유효한 XML 문자 이므로 "\ U00010330"을 반환해야 합니다.

대리 문자를 지원하려면 다음 방법을 사용하는 것이 좋습니다.

public static string RemoveInvalidXmlChars(string text)
{
    if (string.IsNullOrEmpty(text))
        return text;

    int length = text.Length;
    StringBuilder stringBuilder = new StringBuilder(length);

    for (int i = 0; i < length; ++i)
    {
        if (XmlConvert.IsXmlChar(text[i]))
        {
            stringBuilder.Append(text[i]);
        }
        else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i]))
        {
            stringBuilder.Append(text[i]);
            stringBuilder.Append(text[i + 1]);
            ++i;
        }
    }

    return stringBuilder.ToString();
}

4

다음은 위 메서드 RemoveInvalidXmlChars의 최적화 된 버전입니다.이 메서드는 모든 호출에서 새 배열을 만들지 않으므로 GC에 불필요하게 스트레스를줍니다.

public static string RemoveInvalidXmlChars(string text)
{
    if (text == null)
        return text;
    if (text.Length == 0)
        return text;

    // a bit complicated, but avoids memory usage if not necessary
    StringBuilder result = null;
    for (int i = 0; i < text.Length; i++)
    {
        var ch = text[i];
        if (XmlConvert.IsXmlChar(ch))
        {
            result?.Append(ch);
        }
        else if (result == null)
        {
            result = new StringBuilder();
            result.Append(text.Substring(0, i));
        }
    }

    if (result == null)
        return text; // no invalid xml chars detected - return original text
    else
        return result.ToString();

}

?.구문 은 무엇입니까 ? 줄에 result?.Append(ch);?
JB. 모니카 랑.


1
// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\.@-]", ""); 

정규식 패턴 [^ \ w. @-]은 단어 문자, 마침표, @ 기호 또는 하이픈이 아닌 모든 문자와 일치합니다. 단어 문자는 문자, 십진수 또는 밑줄과 같은 구두점 커넥터입니다. 이 패턴과 일치하는 모든 문자는 대체 패턴으로 정의 된 문자열 인 String.Empty로 대체됩니다. 사용자 입력에 추가 문자를 허용하려면 해당 문자를 정규식 패턴의 문자 클래스에 추가하십시오. 예를 들어 정규식 패턴 [^ \ w. @-\ %]은 입력 문자열에 백분율 기호와 백 슬래시도 허용합니다.

Regex.Replace(inputString, @"[!@#$%_]", "");

이것도 참조하십시오 :

XML 이름 태그에서 잘못된 문자 제거-RegEx C #

다음은 지정된 XML 문자열에서 문자를 제거하는 함수입니다.

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace XMLUtils
{
    class Standards
    {
        /// <summary>
        /// Strips non-printable ascii characters 
        /// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
        /// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
        /// </summary>
        /// <param name="content">contents</param>
        /// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param>
        private void StripIllegalXMLChars(string tmpContents, 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(tmpContents))
            {
                tmpContents = regex.Replace(tmpContents, String.Empty);
            }
            tmpContents = string.Empty;
        }
    }
}

0
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
    if (UnfilteredString == null)
        return string.Empty;

    return XmlConvert.EncodeName(UnfilteredString);
}

string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
    if (UnfilteredString == null)
        return string.Empty;

    return XmlConvert.DecodeName(UnfilteredString);
}

이 간단한 방법은 잘못된 문자를 동일한 값으로 대체하지만 XML 컨텍스트에서 허용됩니다.


문자열을 쓰려면 XMLWriteStringWithoutIllegalCharacters (string UnfilteredString)를 사용하십시오.
문자열을 읽으려면 XMLReadStringWithoutIllegalCharacters (string FilteredString)를 사용하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.