[英]XmlSerializer: serializing a class property as an attribute of a custom subelement
我正在使用XmlSerializer
。 我的課:
[Serializable]
[XmlRoot(ElementName="MyClass")]
public class MyClass
{
public string Value;
}
我想序列化它,以便Value
最終作為名為(例如)“Text”的子元素的屬性。
期望的結果:
<MyClass>
<Text Value="3"/>
</MyClass>
但是NOT (將Value標記為XmlAttribute
的效果)
<MyClass Value="3">
</MyClass>
而NOT (將Value標記為XmlElement
的效果):
<MyClass>
<Value>3</Value>
</MyClass>
我該如何實現這一目標?
我知道我可以將Value
的類型從string更改為另一個可序列化的自定義類。
不幸的是,我有很多這樣的屬性,所以我需要創建幾十個小類。
有沒有更快的解決方案?
編輯:
回應你的意見:
不,並非每個屬性都必須序列化為名為“Text”的子元素。 Subelement的名稱是獨特且明確的。
示例輸出XML:
<visibility> <site visible="yes"/> <comparator visible="no"/> <expiration days="7"/> <comment>blahblahblah</comment> <visibility>
樣本類:
!
[XmlRoot(ElementName="Visibility")]
public class Visibility
{
[XPath("/site@visible")] // if only this was possible!
public string OnSite
{
get { return SiteVisible ? "yes" : "no"; }
}
[XPath("/comparator@visible")] // as above...
public string InComparator
{
get { return ComparatorVisible ? "yes" : "no"; }
}
[XmlIgnore]
public bool SiteVisible;
[XmlIgnore]
public bool ComparatorVisible;
[XPath("/expiration@days")] // as above...
public int ExpiresAfterDays;
[XmlElement("comment")] // this is easy
public string Comment;
}
在不改變Value
類型的情況下,我認為這是不可能的。 您可以在Value
上添加屬性XmlElement(ElementName="Text")
,但您將獲得與此類似的結果:
<MyClass>
<Text>3</Text>
</MyClass>
編輯:另一個解決方案可以涉及XSLT轉換:您可以使用.Net序列化生成xml並應用xml轉換。
XslTransform myXslTransform = new XslTransform();
myXslTransform.Load(xsltDoc);
myXslTransform.Transform(sourceDoc, resultDoc);
我的例子的變形應該是這樣的:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="MyClass">
<MyClass>
<Text>
<xsl:attribute name="Value">
<xsl:value-of select="Text"/>
</xsl:attribute>
</Text>
</MyClass>
</xsl:template>
</xsl:stylesheet>
為了這種靈活性,您應該考慮實現IXmlSerializable
因為這樣可以提供更多控制:
[XmlRoot("visibility")]
public class Visibility : IXmlSerializable
{
public string Site;
public string Comparator;
public int Expiration;
public string Comment;
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
// implement me if you want to deserialize too.
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
WriteProperty(writer, "site", "visible", Site);
WriteProperty(writer, "comparator ", "visible", Comparator);
WriteProperty(writer, "expiration ", "days", Expiration);
if (!string.IsNullOrEmpty(Comment))
{
writer.WriteElementString("comment", Comment);
}
}
private void WriteProperty<T>(XmlWriter writer, string elementName, string attibuteName, T value)
{
if (value != null)
{
writer.WriteStartElement(elementName);
writer.WriteAttributeString(attibuteName, value.ToString());
writer.WriteEndElement();
}
}
}
顯然,這里有一些手動工作,但它確實允許您將所有序列化代碼保存在一個地方,而不是增加較小的類。
上面的示例僅實現序列化 - 如果需要從xml反序列化到類型,則需要編寫等效的反序列化實現。
感謝所有的答案。 遺憾的是,.NET XmlSerialization
庫不允許這樣做(我認為它應該!)。 我正在尋找盡可能通用的解決方案。
我能想出的最好的一個(考慮到最大通用性的標准,同時合理地快速實現)是讓XmlSerializer
自己喜歡的方式序列化我的類,然后只需轉換輸出,將某些元素重新定位到嵌套位置。
像這樣的東西:
/// <remarks>
/// (angle brackets replaced with round ones to avoid confusing the XML-based documentation comments format)
///
/// Let input XML be:
///
/// (root)
/// (days)3(/days)
/// (/root)
///
/// Calling Reposition on this input with mappings argument being:
/// (key) "days"
/// (value) { "time", "days" }
///
/// Returns:
/// (root)
/// (time days="3" /)
/// (/root)
/// </remarks>
static XElement Reposition(XElement input, KeyValuePair<string, string[]>[] mappings)
{
var result = new XElement(input);
foreach (var mapping in mappings)
{
var element = result.Element(mapping.Key);
if (element == null)
{
continue;
}
var value = element.Value;
element.Remove();
var insertAt = result;
foreach (var breadcrumb in mapping.Value)
{
if (breadcrumb == mapping.Value.Last())
{
insertAt.Add(new XAttribute(breadcrumb, value));
}
else
{
insertAt.Add(new XElement(breadcrumb));
insertAt = insertAt.Element(breadcrumb);
}
}
}
return result;
}
我想我會將它與自定義屬性(類似於我希望存在的XPath
屬性類似:請參閱我的問題中的示例代碼),並在我自己的序列化程序類中包裝此功能。
對此方法有何評論/見解?
我可以想到一個潛在的性能缺陷(在每次序列化后重寫/重新分析XML),但是由此產生的XML片段預計不會很大,所以這可能是微不足道的。
反序列化的問題在這一點上並沒有打擾我(反序列化已經實現並且通過XPath和一些實用方法完全“手動”完成)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.