programing tip

XML 헤더가 포함 된 경우 C # XmlDocument.LoadXml (string)이 실패하는 이유는 무엇입니까?

itbloger 2020. 12. 3. 07:36
반응형

XML 헤더가 포함 된 경우 C # XmlDocument.LoadXml (string)이 실패하는 이유는 무엇입니까?


다음 코드 샘플이 XmlException "루트 수준의 데이터가 잘못되었습니다. 줄 1, 위치 1"과 함께 실패하는 이유를 아는 사람이 있습니까?

var body = "<?xml version="1.0" encoding="utf-16"?><Report> ......"
XmlDocument bodyDoc = new XmlDocument();            
bodyDoc.LoadXml(body);

배경

귀하의 질문에는 인코딩이 UTF-16으로 설정되어 있지만 문자열이 제대로 이스케이프되지 않았으므로 실제로 문자열을 질문에 정확하게 전치했는지 확실하지 않았습니다.

동일한 예외가 발생했습니다.

System.Xml.XmlException : 루트 수준의 데이터가 잘못되었습니다. 라인 1, 위치 1

그러나 내 코드는 다음과 같습니다.

string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<event>This is a Test</event>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);

문제

문제는 문자열이 .NET에서 내부적으로 UTF-16으로 저장되지만 XML 문서 헤더에 지정된 인코딩이 다를 수 있다는 것입니다. 예 :

<?xml version="1.0" encoding="utf-8"?>

여기 String에 대한 MSDN 문서 에서 :

문자열의 각 유니 코드 문자는 유니 코드 코드 포인트 또는 유니 코드 문자의 서수 (숫자) 값이라고도하는 유니 코드 스칼라 값으로 정의됩니다. 각 코드 포인트는 UTF-16 인코딩을 사용하여 인코딩되며 인코딩의 각 요소의 숫자 값은 Char 개체로 표시됩니다.

즉, XML 헤더가있는 문자열에 XmlDocument.LoadXml ()을 전달할 때 인코딩이 UTF-16이라고 말해야합니다. 그렇지 않으면 실제 기본 인코딩이 헤더에보고 된 인코딩과 일치하지 않아 XmlException이 발생합니다.

해결책

이 문제에 대한 해결책은 Load 또는 LoadXml 메서드를 전달하는 모든 항목에 사용 된 인코딩이 XML 헤더에있는 것과 일치하는지 확인하는 것입니다. 위의 예에서 XML 헤더를 UTF-16 상태로 변경하거나 입력을 UTF-8로 인코딩하고 XmlDocument.Load 메서드 중 하나를 사용 합니다 .

아래는 UTF-8 인코딩 XML 문서를 정의하는 문자열을 사용하여 MemoryStream을 사용하여 XmlDocument를 빌드하는 방법을 보여주는 샘플 코드입니다 (물론 UTF-16 .NET 문자열로 저장 됨).

string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<event>This is a Test</event>";

// Encode the XML string in a UTF-8 byte array
byte[] encodedString = Encoding.UTF8.GetBytes(xml);

// Put the byte array into a stream and rewind it to the beginning
MemoryStream ms = new MemoryStream(encodedString);
ms.Flush();
ms.Position = 0;

// Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);

대신 사용 : 간단하고 효율적인 솔루션 LoadXml()방법의 사용 Load()방법

예를 들면 :

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");

이 시도:

XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);

나는 그것을 알아. MSDN 설명서를 읽으면 문자열에서 읽을 때 LoadXml 대신 .Load를 사용한다고 말합니다. 이것이 100 % 작동한다는 것을 알았습니다. 이상하게도 StringReader를 사용하면 문제가 발생합니다. 주된 이유는 이것이 유니 코드로 인코딩 된 문자열이고 StringReader가 UTF-8 전용이기 때문에 문제를 일으킬 수 있기 때문이라고 생각합니다.

MemoryStream stream = new MemoryStream();
            byte[] data = body.PayloadEncoding.GetBytes(body.Payload);
            stream.Write(data, 0, data.Length);
            stream.Seek(0, SeekOrigin.Begin);

            XmlTextReader reader = new XmlTextReader(stream);

            // MSDN reccomends we use Load instead of LoadXml when using in memory XML payloads
            bodyDoc.Load(reader);

이것은 나를 위해 일했습니다.

var xdoc = new XmlDocument { XmlResolver = null };  
xdoc.LoadXml(xmlFragment);

이것은 정말로 내 하루를 구했습니다.

Zach의 답변을 기반으로 확장 메서드를 작성했으며 인코딩을 매개 변수로 사용하도록 확장하여 UTF-8 이외의 다른 인코딩을 사용할 수 있도록하고 MemoryStream을 'using'문으로 래핑했습니다.

public static class XmlHelperExtentions
{
    /// <summary>
    /// Loads a string through .Load() instead of .LoadXml()
    /// This prevents character encoding problems.
    /// </summary>
    /// <param name="xmlDocument"></param>
    /// <param name="xmlString"></param>
    public static void LoadString(this XmlDocument xmlDocument, string xmlString, Encoding encoding = null) {

        if (encoding == null) {
            encoding = Encoding.UTF8;
        }

        // Encode the XML string in a byte array
        byte[] encodedString = encoding.GetBytes(xmlString);

        // Put the byte array into a stream and rewind it to the beginning
        using (var ms = new MemoryStream(encodedString)) {
            ms.Flush();
            ms.Position = 0;

            // Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
            xmlDocument.Load(ms);
        }
    }
}

I had the same problem when switching from absolute to relative path for my xml file. The following solves both loading and using relative source path issues. Using a XmlDataProvider, which is defined in xaml (should be possible in code too) :

    <Window.Resources>
    <XmlDataProvider 
        x:Name="myDP"
        x:Key="MyData"
        Source=""
        XPath="/RootElement/Element"
        IsAsynchronous="False"
        IsInitialLoadEnabled="True"                         
        debug:PresentationTraceSources.TraceLevel="High"  /> </Window.Resources>

The data provider automatically loads the document once the source is set. Here's the code :

        m_DataProvider = this.FindResource("MyData") as XmlDataProvider;
        FileInfo file = new FileInfo("MyXmlFile.xml");

        m_DataProvider.Document = new XmlDocument();
        m_DataProvider.Source = new Uri(file.FullName);

Simple line:

bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));


I had the same issue because the XML file I was uploading was encoded using UTF-8-BOM (UTF-8 byte-order mark).

Switched the encoding to UTF-8 in Notepad++ and was able to load the XML file in code.

참고URL : https://stackoverflow.com/questions/310669/why-does-c-sharp-xmldocument-loadxmlstring-fail-when-an-xml-header-is-included

반응형