문제

.NET에서 XML 요소 또는 속성에서 사용하기 위해 문자열을 인코딩하는 일반적인 메소드를 찾고 있었고 즉시 찾지 못했을 때 놀랐습니다. 그래서 너무 더 나아 가기 전에 내장 기능을 놓칠 수 있습니까?

실제로 존재하지 않는다고 생각하면 내 자신의 일반적인 것을 모으고 있습니다. EncodeForXml(string data) 방법, 저는이 작업을 수행하는 가장 좋은 방법에 대해 생각하고 있습니다.

이 모든 것을 사용하는 데이터는 &, <, "등과 같은 나쁜 문자를 포함 할 수 있습니다. 때로는 제대로 탈출 한 엔티티를 포함 할 수도 있습니다. 최선의 아이디어가 아닙니다. 그것은 klunky anyay처럼 보입니다. 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

모든 사람들에게 죄송합니다. .그물

마지막으로, 우리는 여전히 내가 일하는 .NET 2.0에 있지만, 누군가가 최종 제품을 가져 와서 문자열 클래스의 확장 방법으로 바꿀 수 있다면 그것은 매우 멋질 것입니다.

업데이트 처음 몇 가지 응답은 .NET은 실제로이를 수행하는 방법이 내장되어 있음을 나타냅니다. 그러나 이제 내가 시작 했으므로, 나는 그것의 재미를 위해 encodeforxml () 메소드를 완료하고 싶기 때문에 여전히 개선을위한 아이디어를 찾고 있습니다. 특히 : 엔티티 (아마도 목록/지도에 저장)로 인코딩되어야하는보다 완전한 문자 목록과 직렬에서 불변의 문자열에서 .replace ()를 수행하는 것보다 더 나은 성능을 얻는 것.

도움이 되었습니까?

해결책

System.xml은 인코딩을 처리하므로 이와 같은 방법이 필요하지 않습니다.

다른 팁

입력에 대해 얼마나 알고 있는지에 따라 모든 유니 코드 문자가 유효한 XML 문자는 아닙니다.

둘 다 Server.htmlencode 그리고 System.Security.securityElement.escape 불법 XML 문자를 무시하는 것 같습니다 System.xml.xmlwriter.writestring 던졌습니다 ArgumentException 불법 문자가 발생할 때 (확인을 비활성화하지 않는 한,이 경우 무시하지 않는 한). 라이브러리 기능에 대한 개요를 사용할 수 있습니다 여기.

편집 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
}

단위 테스트 및 전체 코드를 찾을 수 있습니다 여기.

SecurityElement.escape

문서화 여기

과거에는 httputility.htmlencode를 사용하여 XML의 텍스트를 인코딩했습니다. 실제로 동일한 작업을 수행합니다. 나는 아직 문제를 해결하지 못했지만 앞으로는 내가하지 않을 것이라고 말하는 것은 아닙니다. 이름에서 알 수 있듯이 XML이 아닌 HTML 용으로 만들어졌습니다.

당신은 아마 이미 그것을 읽었을 것입니다 여기에 기사가 있습니다 XML 인코딩 및 디코딩.

편집 : 물론 XMLWriter 또는 새로운 Xlement 클래스 중 하나를 사용하는 경우이 인코딩이 수행됩니다. 실제로 텍스트를 가져 와서 새 Xlement 인스턴스에 배치 한 다음 String (.toString) 버전의 요소를 반환 할 수 있습니다. 나는 그 말을 들었다 SecurityElement.escape 유틸리티 방법과 동일한 작업을 수행하지만 그것에 대해 많이 읽거나 사용하지 않았습니다.

edit2 : xlement에 대한 내 의견을 무시합니다.

마이크로 소프트 Antixss 라이브러리 antixssencoder 클래스 System.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() 탈출.

이것이 ASP.NET 앱 인 경우 Server.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>

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

훌륭한! 그게 내가 말할 수있는 전부입니다.

다음은 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;"}}

내장 클래스를 사용할 수 있습니다 xattribute, 인코딩을 자동으로 처리합니다.

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

아 그리고 그것은 C#이 아닌 VB에서만 작동합니다.

취급에 대해 진지한 경우 모두 유효하지 않은 문자 중 일부는 "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-encode가 필요할 때 URL 인코딩과 같습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top