source

XML용 텍스트 데이터를 인코딩하는 가장 좋은 방법

factcode 2023. 10. 11. 21:03
반응형

XML용 텍스트 데이터를 인코딩하는 가장 좋은 방법

에서 일반적인 방법을 찾고 있었습니다.XML 요소 또는 특성에 사용할 문자열을 인코딩하기 위한 Net이며, 문자열을 즉시 찾지 못했을 때 깜짝 놀랐습니다.그럼 너무 멀리 가기 전에 내장된 기능을 놓치면 안 되는 건가요?

존재하지 않는다는 가정하고,인 인 입니다를 EncodeForXml(string data)방법과 방법을 생각하고 있습니다.

제가 사용하고 있는 데이터가 이 모든 것을 촉발시켰기 때문에 &, <, <, " 등과 같은 나쁜 문자가 포함되어 있을 수 있습니다.또한 적절히 탈출된 엔티티(&amp;, &lt; 및 &quot;)를 포함할 수도 있는데, 이는 단지 CDATA 섹션을 사용하는 것이 최선의 방법이 아닐 수도 있음을 의미합니다.어쨌든 그건 좀 투박해 보이네요; 차라리 xml에 직접 사용할 수 있는 멋진 문자열 값으로 끝내고 싶네요.

예전에 그냥 나쁜 앰퍼샌드를 잡을 때 일반적인 표현을 사용한 적이 있는데, 이 경우는 물론 첫 번째 단계에서도 그것을 잡을 때 사용하고, 그 다음에 다른 캐릭터를 간단한 교체를 해볼까 생각 중입니다.

그럼 너무 복잡하지 않게 최적화할 수 있을까요? 그리고 제가 놓친 부분이 있나요?:

Function EncodeForXml(ByVal data As String) As String
    Static badAmpersand As new Regex("&(?![a-zA-Z]{2,6};|#[0-9]{2,4};)")

    data = badAmpersand.Replace(data, "&amp;")

    return data.Replace("<", "&lt;").Replace("""", "&quot;").Replace(">", "gt;")
End Function

C#-only pleople-- 제가 어떤 언어를 쓰든 상관없지만, 저는 Regex를 정적으로 만들고 싶었고, C#에서는 메소드 밖에서 선언하지 않으면 그렇게 할 수 없기 때문에, 이것은 VB.Net이 될 것입니다.

드디어 저희가.제가 일하는 곳에서는 넷 2.0이지만, 만약 누군가가 최종 제품을 가져가서 스트링 클래스의 확장 방법으로 바꿀 수 있다면, 그것 또한 꽤 멋질 것입니다.

업데이트 처음 몇 개의 응답은 다음을 나타냅니다.Net에는 실제로 이러한 작업을 수행하는 방법이 내장되어 있습니다.하지만 이제 시작한 이상, 저는 단지 재미를 위해서 EncodesForXml() 방법을 끝내고 싶어서 아직도 개선 방안을 찾고 있습니다.특히: 엔티티로 인코딩되어야 하는 문자의 보다 완전한 목록(아마도 목록/맵에 저장됨)과 을 수행하는 것보다 성능이 향상되는 것.일련의 불변 문자열에서 ()를 바꿉니다.

입력에 대해 아는 정도에 따라 모든 유니코드 문자가 유효한 XML 문자가 아님을 고려해야 할 수도 있습니다.

서버 모두.HtmlEncode시스템.보안.보안 요소.이스케이프는 잘못된 XML 문자를 무시하는 반면 시스템.XML.XmlWriter.WriteString인수를 던집니다.불법 문자가 발견된 경우 예외(해당 검사를 비활성화하지 않는 경우 무시됨).도서관 기능에 대한 개요는 여기에서 볼 수 있습니다.

편집 2011/8/14: 지난 몇 년 동안 적어도 몇 명의 사람들이 이 답변을 상담한 것을 보고, 저는 원래의 코드를 완전히 다시 쓰기로 결정했는데, UTF-16을 심각하게 잘못 다루는 을 포함하여 많은 문제가 있었습니다.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

/// <summary>
/// Encodes data so that it can be safely embedded as text in XML documents.
/// </summary>
public class XmlTextEncoder : TextReader {
    public static string Encode(string s) {
        using (var stream = new StringReader(s))
        using (var encoder = new XmlTextEncoder(stream)) {
            return encoder.ReadToEnd();
        }
    }

    /// <param name="source">The data to be encoded in UTF-16 format.</param>
    /// <param name="filterIllegalChars">It is illegal to encode certain
    /// characters in XML. If true, silently omit these characters from the
    /// output; if false, throw an error when encountered.</param>
    public XmlTextEncoder(TextReader source, bool filterIllegalChars=true) {
        _source = source;
        _filterIllegalChars = filterIllegalChars;
    }

    readonly Queue<char> _buf = new Queue<char>();
    readonly bool _filterIllegalChars;
    readonly TextReader _source;

    public override int Peek() {
        PopulateBuffer();
        if (_buf.Count == 0) return -1;
        return _buf.Peek();
    }

    public override int Read() {
        PopulateBuffer();
        if (_buf.Count == 0) return -1;
        return _buf.Dequeue();
    }

    void PopulateBuffer() {
        const int endSentinel = -1;
        while (_buf.Count == 0 && _source.Peek() != endSentinel) {
            // Strings in .NET are assumed to be UTF-16 encoded [1].
            var c = (char) _source.Read();
            if (Entities.ContainsKey(c)) {
                // Encode all entities defined in the XML spec [2].
                foreach (var i in Entities[c]) _buf.Enqueue(i);
            } else if (!(0x0 <= c && c <= 0x8) &&
                       !new[] { 0xB, 0xC }.Contains(c) &&
                       !(0xE <= c && c <= 0x1F) &&
                       !(0x7F <= c && c <= 0x84) &&
                       !(0x86 <= c && c <= 0x9F) &&
                       !(0xD800 <= c && c <= 0xDFFF) &&
                       !new[] { 0xFFFE, 0xFFFF }.Contains(c)) {
                // Allow if the Unicode codepoint is legal in XML [3].
                _buf.Enqueue(c);
            } else if (char.IsHighSurrogate(c) &&
                       _source.Peek() != endSentinel &&
                       char.IsLowSurrogate((char) _source.Peek())) {
                // Allow well-formed surrogate pairs [1].
                _buf.Enqueue(c);
                _buf.Enqueue((char) _source.Read());
            } else if (!_filterIllegalChars) {
                // Note that we cannot encode illegal characters as entity
                // references due to the "Legal Character" constraint of
                // XML [4]. Nor are they allowed in CDATA sections [5].
                throw new ArgumentException(
                    String.Format("Illegal character: '{0:X}'", (int) c));
            }
        }
    }

    static readonly Dictionary<char,string> Entities =
        new Dictionary<char,string> {
            { '"', "&quot;" }, { '&', "&amp;"}, { '\'', "&apos;" },
            { '<', "&lt;" }, { '>', "&gt;" },
        };

    // References:
    // [1] http://en.wikipedia.org/wiki/UTF-16/UCS-2
    // [2] http://www.w3.org/TR/xml11/#sec-predefined-ent
    // [3] http://www.w3.org/TR/xml11/#charsets
    // [4] http://www.w3.org/TR/xml11/#sec-references
    // [5] http://www.w3.org/TR/xml11/#sec-cdata-sect
}

유닛 테스트와 풀 코드는 여기서 확인할 수 있습니다.

보안 요소.탈출하다

여기에 기록된

나는 과거에 HttpUtility를 사용한 적이 있습니다.xml에 대한 텍스트를 인코딩하는 HtmlEncode입니다.그것은 정말로 같은 일을 합니다.저는 아직 그것과 관련된 문제에 부딪힌 적은 없지만, 그렇다고 해서 앞으로 안 하겠다는 것은 아닙니다.이름에서 알 수 있듯이 XML이 아닌 HTML을 위해 만들어졌습니다.

아마 이미 읽으셨겠지만, 여기 xml 인코딩과 디코딩에 관한 기사가 있습니다.

편집: 물론 xmlwriter 또는 새로운 XElement 클래스 중 하나를 사용하는 경우 이 인코딩이 수행됩니다.실제로 텍스트를 가져와 새 XElement 인스턴스에 배치한 다음 요소의 문자열(.tostring) 버전을 반환할 수 있습니다.시큐리티 엘레먼트라고 들었습니다.이스케이프는 유틸리티 메소드와 동일한 작업을 수행하지만, 이에 대해 많이 읽거나 사용하지 않았습니다.

EDIT2: XElement에 대한 제 의견은 무시합니다. 아직 2.0을 사용하고 있습니다.

마이크로소프트사 AntiXss 라이브러리시스템의 AntiXss 인코더 클래스입니다.Web.dll에는 다음과 같은 메소드가 있습니다.

AntiXss.XmlEncode(string s)
AntiXss.XmlAttributeEncode(string s)

HTML도 있습니다.

AntiXss.HtmlEncode(string s)
AntiXss.HtmlAttributeEncode(string s)

인.net 3.5+

new XText("I <want> to & encode this for XML").ToString();

다음을 제공:

I &lt;want&gt; to &amp; encode this for XML

이 메서드는 따옴표와 같은 일부 항목을 인코딩하지 않는 것으로 나타났습니다.

SecurityElement.Escape(workmad3의 답변은) 이것으로 더 잘 할 수 있을 것 같고 이전 버전의 .net에 포함되어 있습니다.

타사 코드를 신경 쓰지 않고 불법 문자가 사용자의 XML에 들어가지 않도록 하고 싶다면 마이클 크로파트의 답변을 추천합니다.

XmlTextWriter.WriteString()탈출을 합니다.

System.XML은 인코딩을 대신 처리하므로 이러한 메서드는 필요하지 않습니다.

ASP라면.NET 앱 서버를 사용하지 않는 이유.HtmlEncode() ?

WriteCData 메서드를 사용하면 이점을 얻을 수 있습니다.

public override void WriteCData(string text)
    Member of System.Xml.XmlTextWriter

Summary:
Writes out a <![CDATA[...]]> block containing the specified text.

Parameters:
text: Text to place inside the CDATA block.

간단한 예는 다음과 같습니다.

writer.WriteStartElement("name");
writer.WriteCData("<unsafe characters>");
writer.WriteFullEndElement();

결과는 다음과 같습니다.

<name><![CDATA[<unsafe characters>]]></name>

노드 값을 읽을 때 내부 텍스트의 CD 데이터 부분을 XML Reader가 자동으로 제거하여 걱정할 필요가 없습니다.유일한 문제점은 XML 노드에 데이터를 내부 텍스트 값으로 저장해야 한다는 것입니다.즉, CData 컨텐츠를 속성 값에 삽입할 수 없습니다.

유효하지 않은 모든 문자를 처리하려는 경우( 안 되는 "html" 문자만 처리하는 것이 아니라)에 액세스할 수 있습니다.System.Xml, 값 데이터의 적절한 XML 인코딩을 수행하는 가장 간단한 방법은 다음과 같습니다.

string theTextToEscape = "Something \x1d else \x1D <script>alert('123');</script>";
var x = new XmlDocument();
x.LoadXml("<r/>"); // simple, empty root element
x.DocumentElement.InnerText = theTextToEscape; // put in raw string
string escapedText = x.DocumentElement.InnerXml; // Returns:  Something &#x1D; else &#x1D; &lt;script&gt;alert('123');&lt;/script&gt;

// Repeat the last 2 lines to escape additional strings.

합니다를 XmlConvert.EncodeName()값이 아닌 엔티티/태그 이름을 위한 것이기 때문에 적절치 않습니다.그것을 사용하는 것은 HTML 인코딩이 필요할 때 URL 인코딩과 같습니다.

훌륭합니다!제가 할 말은 그게 다예요.

다음은 xml을 정리하고 검사할 업데이트된 코드(클래스가 아닌 함수)의 VB 변형입니다.

Function cXML(ByVal _buf As String) As String
    Dim textOut As New StringBuilder
    Dim c As Char
    If _buf.Trim Is Nothing OrElse _buf = String.Empty Then Return String.Empty
    For i As Integer = 0 To _buf.Length - 1
        c = _buf(i)
        If Entities.ContainsKey(c) Then
            textOut.Append(Entities.Item(c))
        ElseIf (AscW(c) = &H9 OrElse AscW(c) = &HA OrElse AscW(c) = &HD) OrElse ((AscW(c) >= &H20) AndAlso (AscW(c) <= &HD7FF)) _
            OrElse ((AscW(c) >= &HE000) AndAlso (AscW(c) <= &HFFFD)) OrElse ((AscW(c) >= &H10000) AndAlso (AscW(c) <= &H10FFFF)) Then
            textOut.Append(c)
        End If
    Next
    Return textOut.ToString

End Function

Shared ReadOnly Entities As New Dictionary(Of Char, String)() From {{""""c, "&quot;"}, {"&"c, "&amp;"}, {"'"c, "&apos;"}, {"<"c, "&lt;"}, {">"c, "&gt;"}}

인코딩을 자동으로 처리하는 내장 클래스 XA속성을 사용할 수 있습니다.

using System.Xml.Linq;

XDocument doc = new XDocument();

List<XAttribute> attributes = new List<XAttribute>();
attributes.Add(new XAttribute("key1", "val1&val11"));
attributes.Add(new XAttribute("key2", "val2"));

XElement elem = new XElement("test", attributes.ToArray());

doc.Add(elem);

string xmlStr = doc.ToString();

XElements를 사용하는 단일 라인 솔루션은 다음과 같습니다.아주 작은 도구로 사용합니다.두번 다시 필요없으니까 이대로 놔둬요. (더럽기만 한 더그)

StrVal = (<x a=<%= StrVal %>>END</x>).ToString().Replace("<x a=""", "").Replace(">END</x>", "")

아 그리고 VB에서만 작동되고 C#에서는 작동되지 않습니다.

언급URL : https://stackoverflow.com/questions/157646/best-way-to-encode-text-data-for-xml

반응형