5

何でもできる application/xml ファイルや、すべての空白シーケンスを単一の空白文字に変換する normalizedString 値とは対照的に、ここでは文字列値を持つ text/xml ファイルのコンテキストで具体的に質問しています。簡単にするために、UTF8 でエンコードされたファイルで ASCII 文字のみを使用しているとしましょう。

次の 2 行のテキスト文字列を XML で表現したいとします。

Hello
World!

メモリ内の次のバイトは次のとおりです。

0000: 48 65 6c 6c 6f 0d 0a 57 6f 72 6c 64 21 Hello..World!

RFC 2046 によると、任意の text/* MIME タイプは、キャリッジ リターンとそれに続くラインフィード文字シーケンスを使用して改行を表現しなければなりません (すべきではありません)。その観点から、次の XML フラグメントは正しいはずです。

<tag>Hello
World!</tag>

また

0000: 3c 74 61 67 3c 48 65 6c 6c 6f 0d 0a 57 6f 72 6c <tag>Hello..Worl
0010: 64 21 3c 2f 74 61 67 3c                         d!</tag>

しかし、私は定期的に次のようなファイルを目にします。

<tag><![CDATA[Hello
World!]]></tag>

または、さらに見知らぬ人:

<tag>Hello&xD;
World!</tag>

&0xD; シーケンスの後には単一の改行文字が続きます。

0000: 3c 74 61 67 3c 48 65 6c 6c 6f 26 78 44 3b 0a 57 <tag>Hello&xD;.W
0010: 6f 72 6c 64 21 3c 2f 74 61 67 3c                orld!</tag>

ここで何が欠けていますか?XML 文字列値で複数行のテキストを表現して、相手が邪魔されないようにする正しい方法は何ですか?

4

3 に答える 3

4

CR (&x0D;)、LF (&x0A;)、CRLF、またはその他のいくつかの組み合わせはすべて有効です。仕様に記載されているように、これらはすべて単一の &x0A; に変換されます。キャラクター。

于 2013-02-22T02:51:57.470 に答える
3

Mono で NUnit テストを記述し、Java で JUnit テストを記述した後、答えは <tag>Hello \nWorld!</tag> または <tag>Hello \nWorld!</tag> のいずれかを使用するように見えます。以下のように...

Foo.cs:

using System.IO;
using System.Text;
using System.Xml.Serialization;

namespace XmlStringTests
{
    public class Foo
    {
        public string greeting;

        public static Foo DeserializeFromXmlString (string xml)
        {
            Foo result;
            using (MemoryStream memoryStream = new MemoryStream()) {
                byte[] buffer = Encoding.UTF8.GetBytes (xml);
                memoryStream.Write (buffer, 0, buffer.Length);
                memoryStream.Seek (0, SeekOrigin.Begin);
                XmlSerializer xs = new XmlSerializer (typeof(Foo));
                result = (Foo)xs.Deserialize (memoryStream);
            }
            return result;
        }
    }
}

XmlStringTests.cs:

using NUnit.Framework;

namespace XmlStringTests
{
    [TestFixture]
    public class XmlStringTests
    {
        const string expected = "Hello\u000d\u000aWorld!";

        [Test(Description="Fails")]
        public void Cdata ()
        {
            const string test = "<Foo><greeting><![CDATA[Hello\u000d\u000aWorld!]]></greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }

        [Test(Description="Fails")]
        public void CdataWithHash13 ()
        {
            const string test = "<Foo><greeting><![CDATA[Hello&#13;\u000aWorld!]]></greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }

        [Test(Description="Fails")]
        public void CdataWithHashxD ()
        {
            const string test = "<Foo><greeting><![CDATA[Hello&#xd;\u000aWorld!]]></greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }

        [Test(Description="Fails")]
        public void Simple ()
        {
            const string test = "<Foo><greeting>Hello\u000d\u000aWorld!</greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }

        [Test(Description="Passes")]
        public void SimpleWithHash13 ()
        {
            const string test = "<Foo><greeting>Hello&#13;\u000aWorld!</greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }

        [Test(Description="Passes")]
        public void SimpleWithHashxD ()
        {
            const string test = "<Foo><greeting>Hello&#xd;\u000aWorld!</greeting></Foo>";
            Foo bar = Foo.DeserializeFromXmlString (test);
            Assert.AreEqual (expected, bar.greeting);
        }
    }
}

Foo.java:

import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "Foo")
@XmlType(propOrder = { "greeting" })
public class Foo {
    public String greeting;

    public static Foo DeserializeFromXmlString(String xml) {
        try {
            JAXBContext context = JAXBContext.newInstance(Foo.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            Foo foo = (Foo) unmarshaller.unmarshal(new StringReader(xml));
            return foo;
        } catch (JAXBException e) {
            e.printStackTrace();
            return null;
        }
    }
}

XmlStringTests.java:

import static org.junit.Assert.*;
import org.junit.Test;


public class XmlStringTests {
    String expected = "Hello\r\nWorld!";

    @Test //Fails
    public void testCdata ()
    {
        String test = "<Foo><greeting><![CDATA[Hello\r\nWorld!]]></greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }

    @Test //Fails
    public void testCdataWithHash13 ()
    {
        String test = "<Foo><greeting><![CDATA[Hello&#13;\nWorld!]]></greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }

    @Test //Fails
    public void testCdataWithHashxD ()
    {
        String test = "<Foo><greeting><![CDATA[Hello&#xd;\nWorld!]]></greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }

    @Test //Fails
    public void testSimple ()
    {
        String test = "<Foo><greeting>Hello\r\nWorld!</greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }

    @Test //Passes
    public void testSimpleWithHash13 ()
    {
        String test = "<Foo><greeting>Hello&#13;\nWorld!</greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }

    @Test //Passes
    public void testSimpleWithHashxD ()
    {
        String test = "<Foo><greeting>Hello&#xd;\nWorld!</greeting></Foo>";
        Foo bar = Foo.DeserializeFromXmlString (test);
        assertEquals (expected, bar.greeting);
    }
}

これにより、一部の人々が時間を節約できることを願っています。

于 2013-03-22T12:06:31.467 に答える
0

<![CDATA 要素で機能する唯一の解決策は、XML を渡す前に CR を GUID のテキストに文字列置換し、検索後に GUID を CR に戻すことでした。

固定のエスケープ シーケンスではなく GUID を使用すると、既に存在するデータと誤って衝突する可能性がなくなります。

于 2021-07-26T07:49:59.507 に答える