XmlSerializer kullanarak bir dizeyi CDATA olarak nasıl serileştirirsiniz?


92

Net XmlSerializer kullanarak bir dizgeyi CDATA olarak serileştirmek bir tür öznitelikle mümkün müdür?


2
İki yanıtla ilgili kayda değer bir şey CDataContent, yalnızca XML okuyorsanız ihtiyacınız olmamasıdır. XmlSerializer.Deserializesizin için otomatik olarak metne dönüştürecektir.
Chris S

Yanıtlar:


62
[XmlRoot("root")]
public class Sample1Xml
{
    internal Sample1Xml()
    {
    }

    [XmlElement("node")]
    public NodeType Node { get; set; }

    #region Nested type: NodeType

    public class NodeType
    {
        [XmlAttribute("attr1")]
        public string Attr1 { get; set; }

        [XmlAttribute("attr2")]
        public string Attr2 { get; set; }

        [XmlIgnore]
        public string Content { get; set; }

        [XmlText]
        public XmlNode[] CDataContent
        {
            get
            {
                var dummy = new XmlDocument();
                return new XmlNode[] {dummy.CreateCDataSection(Content)};
            }
            set
            {
                if (value == null)
                {
                    Content = null;
                    return;
                }

                if (value.Length != 1)
                {
                    throw new InvalidOperationException(
                        String.Format(
                            "Invalid array length {0}", value.Length));
                }

                Content = value[0].Value;
            }
        }
    }

    #endregion
}

9
Bana göre bu en zarif çözüm gibi görünmüyor. Bunu yapmanın tek yolu bu mu?
jamesaharvey

1
Sanırım bunu başarmanın tek yolu bu, bu konuyu başka yerlerde gördüm ve hep aynı cevabı aldım. Philip'ten örnek biraz daha temiz ama aynı kavram. Bildiğim diğer tek yol, kendi <a href=" msdn.microsoft.com/en-us/library/…>
nizi

Aynı şeyi yapmak istedim çünkü CDATA daha az işlem süresi anlamına geldiği için dizeleri depolamak gibi görünüyor, çünkü onunla 'sadece' dizeyi 'olduğu gibi okuyabilir / yazabiliriz. XmlDocument / XmlCDataSection örneklerini dahil etmek ne kadar pahalı?
tishma

Ve tüm Nitelikler olayı oradadır, böylece etki alanı modeli sınıflarını serileştirme mantık ayrıntılarından temiz tutabiliriz. Tek yol kirli yol ise çok üzücü.
tishma

2
Philip'in çözümü sayfanın biraz daha aşağısındaki daha derli toplu bir iştir.
Karl

100
[Serializable]
public class MyClass
{
    public MyClass() { }

    [XmlIgnore]
    public string MyString { get; set; }
    [XmlElement("MyString")]
    public System.Xml.XmlCDataSection MyStringCDATA
    {
        get
        {
            return new System.Xml.XmlDocument().CreateCDataSection(MyString);
        }
        set
        {
            MyString = value.Value;
        }
    }
}

Kullanım:

MyClass mc = new MyClass();
mc.MyString = "<test>Hello World</test>";
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
StringWriter writer = new StringWriter();
serializer.Serialize(writer, mc);
Console.WriteLine(writer.ToString());

Çıktı:

<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <MyString><![CDATA[<test>Hello World</test>]]></MyString>
</MyClass>

Bu sadece günümü kurtardı. Teşekkür ederim.
Robert

4
// Boş CDATA'ya ihtiyacınız olması durumunda, istisnayı önlemek için kaynak değeri null ise varsayılanı ayarlayabilirsiniz. XmlDocument().CreateCDataSection(MyString ?? String.Empty);
Asereware

@ pr0gg3r bu aynı nesneye seriyi kaldırmaya da izin veriyor mu? Bununla ilgili sorun yaşıyorum
Martin

<MyClass> <! [CDATA [<test> Hello World </test>]]> </MyClass> gibi bir metin değeri (ve bir öğe olarak değil) olarak CDATA nasıl oluşturulur?
mko

1
<emptyfield><![CDATA[]]> </emptyfield>
bluee

91

John Saunders tarafından gönderilen yönteme ek olarak, XmlCDataSection'ı doğrudan tür olarak kullanabilirsiniz , ancak neredeyse aynı şeyi ifade eder:

private string _message;
[XmlElement("CDataElement")]
public XmlCDataSection Message
{  
    get 
    { 
        XmlDocument doc = new XmlDocument();
        return doc.CreateCDataSection( _message);
    }
    set
    {
        _message = value.Value;
    }
}

1
@Philip, bu seriyi kaldırma için çalışıyor mu? Ayarlayıcının bir XmlText değeri alacağını söyleyen notlar görüyorum.
John Saunders 04

1
@John Saunders - Serileştirme sırasında ayarlayıcıda bir XmlCharacterData değeri alır, bu, ayarlayıcıdaki değer için yapılan çağrıdır (başlangıçta bellekten ToString () olarak kullandım, ancak bu yanlıştı.)
Philip Rieck

1
@PhilipRieck Özel bir nesneyi bir CDataSection etrafına sarmamız gerekirse ne olacak? CDataSection Oluştur, dizeyi kabul eder.
zeppelin

Teşekkür ederim! En kolay çözüm. Benim için iyi çalışıyor.
Antonio Rodríguez

43

Serileştirilecek sınıfta:

public CData Content { get; set; }

Ve CData sınıfı:

public class CData : IXmlSerializable
{
    private string _value;

    /// <summary>
    /// Allow direct assignment from string:
    /// CData cdata = "abc";
    /// </summary>
    /// <param name="value">The string being cast to CData.</param>
    /// <returns>A CData object</returns>
    public static implicit operator CData(string value)
    {
        return new CData(value);
    }

    /// <summary>
    /// Allow direct assignment to string:
    /// string str = cdata;
    /// </summary>
    /// <param name="cdata">The CData being cast to a string</param>
    /// <returns>A string representation of the CData object</returns>
    public static implicit operator string(CData cdata)
    {
        return cdata._value;
    }

    public CData() : this(string.Empty)
    {
    }

    public CData(string value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value;
    }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        _value = reader.ReadElementString();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteCData(_value);
    }
}

Tıkır tıkır çalışıyor. Teşekkür ederim.
Leonel Sanches da Silva

3
Bu cevap daha fazla tanınmayı hak ediyor. Bununla birlikte, özelleştirilmiş CData türü artık System.String türünün sahip olduğu kullanışlı yerleşik yöntemlere sahip değildir.
Lionet Chen

güzel, sonra ilk cevap
Hsin-Yu Chen

Cevap harika çalışıyor. XmlElement'in string alanında çalışmaması utanç verici, o zaman sadece bir cdata türü ekleyebilirsiniz, ama her neyse ...
jjxtra

Mükemmel! Teşekkürler!
Roy

5

Benzer bir ihtiyacım vardı ancak farklı bir çıktı formatı gerekiyordu - CDATA'yı içeren düğümde bir öznitelik istedim. Kendi çözümümü yaratmak için yukarıdaki çözümlerden biraz ilham aldım. Belki gelecekte birine yardımcı olur ...

public class EmbedScript
{
    [XmlAttribute("type")]
    public string Type { get; set; }

    [XmlText]
    public XmlNode[] Script { get; set; }

    public EmbedScript(string type, string script)
    {
        Type = type;
        Script = new XmlNode[] { new XmlDocument().CreateCDataSection(script) };
    }

    public EmbedScript()
    {

    }
}

Serileştirilecek üst nesnede aşağıdaki özelliğe sahibim:

    [XmlArray("embedScripts")]
    [XmlArrayItem("embedScript")]
    public List<EmbedScript> EmbedScripts { get; set; }

Aşağıdaki çıktıyı alıyorum:

<embedScripts>
    <embedScript type="Desktop Iframe">
        <![CDATA[<div id="play_game"><iframe height="100%" src="http://www.myurl.com" width="100%"></iframe></div>]]>
    </embedScript>
    <embedScript type="JavaScript">
        <![CDATA[]]>
    </embedScript>
</embedScripts>

1
Bunu tam olarak yapmam gerekiyordu. Teşekkür ederim!!
Lews Therin

4

Benim durumumda karışık alanlar kullanıyorum, bazıları CDATA bazıları değil, en azından benim için aşağıdaki çözüm çalışıyor ....

Değer alanını her zaman okuyarak, ister CDATA ister sadece düz metin olsun, içeriği alıyorum.

    [XmlElement("")]
    public XmlCDataSection CDataValue {
        get {
            return new XmlDocument().CreateCDataSection(this.Value);
        }
        set {
            this.Value = value.Value;
        }
    }

    [XmlText]
    public string Value;

Geç olsun güç olmasın.

Şerefe


Harika - Bu cevabın bana zaman kazandırdığını hissediyorum! Bilgi için Value
d219

Bu işlemsel olarak pr0gg3r'nin cevabından nasıl farklıdır ?
40'ta ruffin

2

Bu uygulama, kodladığınız dizede yuvalanmış CDATA işleme yeteneğine sahiptir (John Saunders orijinal cevabına göre).

Örneğin, aşağıdaki değişmez dizeyi CDATA'ya kodlamak istediğinizi varsayalım:

I am purposefully putting some <![CDATA[ cdata markers right ]]> in here!!

Ortaya çıkan çıktının şöyle görünmesini istersiniz:

<![CDATA[I am purposefully putting some <![CDATA[ cdata markers right ]]]]><![CDATA[> in here!!]]>

Aşağıdaki uygulama, dizi üzerinde döngü oluşturacak, örneklerini ...]]>...bölünecek ...]]ve >...her biri için ayrı CDATA bölümleri oluşturacaktır.

[XmlRoot("root")]
public class Sample1Xml
{
    internal Sample1Xml()
    {
    }

    [XmlElement("node")]
    public NodeType Node { get; set; }

    #region Nested type: NodeType

    public class NodeType
    {
        [XmlAttribute("attr1")]
        public string Attr1 { get; set; }

        [XmlAttribute("attr2")]
        public string Attr2 { get; set; }

        [XmlIgnore]
        public string Content { get; set; }

        [XmlText]
        public XmlNode[] CDataContent
        {
            get
            {
                XmlDocument dummy = new XmlDocument();
                List<XmlNode> xmlNodes = new List<XmlNode>();
                int tokenCount = 0;
                int prevSplit = 0;
                for (int i = 0; i < Content.Length; i++)
                {
                    char c = Content[i];
                    //If the current character is > and it was preceded by ]] (i.e. the last 3 characters were ]]>)
                    if (c == '>' && tokenCount >= 2)
                    {
                        //Put everything up to this point in a new CData Section
                        string thisSection = Content.Substring(prevSplit, i - prevSplit);
                        xmlNodes.Add(dummy.CreateCDataSection(thisSection));
                        prevSplit = i;
                    }
                    if (c == ']')
                    {
                        tokenCount++;
                    }
                    else
                    {
                        tokenCount = 0;
                    }
                }
                //Put the final part of the string into a CData section
                string finalSection = Content.Substring(prevSplit, Content.Length - prevSplit);
                xmlNodes.Add(dummy.CreateCDataSection(finalSection));

                return xmlNodes.ToArray();
            }
            set
            {
                if (value == null)
                {
                    Content = null;
                    return;
                }

                if (value.Length != 1)
                {
                    throw new InvalidOperationException(
                        String.Format(
                            "Invalid array length {0}", value.Length));
                }

                Content = value[0].Value;
            }
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.