xml元素列表到公共基类型的数组

时间:2011-04-11 12:07:37

标签: c# inheritance xml-serialization

我有一个xml文件,其中包含如下列表:

<TestFile>
  <string>Foo</string>
  <bool>false</bool>
  <bool>true</bool>
  <string>Bar</string>
</TestFile>

我想将其反序列化为“Value”类型的数组。该类型有两个子类型“ValueString”和“ValueBool”:

[XmlRoot("TestFile")]
public class TestFile
{
    public List<Test> Tests;
}

public class Value
{
}

public class ValueString : Value
{
    [XmlText]
    public string Value;
}

public class ValueBool : Value
{
    [XmlText]
    public bool Value;
}

我无法弄清楚如何做到这一点。我已经尝试过XmlIncludeAttributes,但这还不够,因为元素名称与类名不匹配。我已经尝试过XmlChoiceIdentifier,但是当我调整它们时,我发现的例子没有编译......

我需要保留元素的顺序,因此将元素分成两个列表是行不通的。我也无法改变xml结构,因为它来自外部源。显然这只是一个例子 - 我的真实类型更复杂......

2 个答案:

答案 0 :(得分:2)

我终于偶然发现了解决方案:

[XmlRoot("TestFile")]
public class TestFile
{
    [XmlElement(ElementName = "string", Type = typeof(ValueString))]
    [XmlElement(ElementName = "bool", Type = typeof(ValueBool))]
    public List<Test> Tests;
}

我以为我之前尝试过......好吧,至少它现在有用了。此示例还有另一个问题:您不能将布尔字段映射到元素文本,但是在我的真实场景中不存在该特定问题......

答案 1 :(得分:2)

通常我们发现自己必须转换提供给我们的XML文件。是的,如果每个人都订购相同的结构会很好,但在中型到大型公司,这可能更难实现。

我从你的XML文件开始:

<?xml version="1.0" encoding="utf-8" ?>
<TestFile>
  <string>Foo</string>
  <bool>false</bool>
  <bool>true</bool>
  <string>Bar</string>
</TestFile>

然后创建了转换文件(这只是一个示例,完全取决于您自己的喜好):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
      <xsl:copy>
        <ParameterCollection>
          <xsl:apply-templates select="@* | node()"/>
        </ParameterCollection>
      </xsl:copy>
  </xsl:template>
  <xsl:template match="bool">
    <Parameter type="bool">
      <xsl:apply-templates select="node()"/>
    </Parameter>
  </xsl:template>
  <xsl:template match="string">
    <Parameter type="string">
      <xsl:apply-templates select="node()"/>
    </Parameter>
  </xsl:template>
</xsl:stylesheet>

然后我开始拼凑所有必要的类:

[XmlRootAttribute("TestFile", IsNullable = false)]
public class TestFile
{
    [XmlArrayAttribute("ParameterCollection")]
    public Parameter[] Parameters;
}

public class Parameter
{
    [XmlAttribute("type")]
    public string ObjectType;

    [XmlText]
    public string ObjectValue;
}

然后应用所有内容(希望以比我更周到的方式):

class Program
{
    static void Main(string[] args)
    {
        FileInfo xmlFile = new FileInfo(@"Resources\TestFile.xml");
        FileInfo transformFile = new FileInfo(@"Resources\TestFileTransform.xslt");
        FileInfo prettyFile = new FileInfo(@"Resources\PrettyFile.xml");

        if (xmlFile.Exists && transformFile.Exists)
        {
            // Perform transform operations.
            XslCompiledTransform trans = new XslCompiledTransform();
            trans.Load(transformFile.FullName);
            trans.Transform(xmlFile.FullName, prettyFile.FullName);
        }

        if (prettyFile.Exists)
        {
            // Deserialize the new information.
            XmlSerializer serializer = new XmlSerializer(typeof(TestFile));
            XDocument doc = XDocument.Load(prettyFile.FullName);
            TestFile o = (TestFile)serializer.Deserialize(doc.CreateReader());

            // Show the results.
            foreach (Parameter p in o.Parameters)
            {
                Console.WriteLine("{0}: {1}", p.ObjectType, p.ObjectValue);
            }
        }

        // Pause for effect.
        Console.ReadKey();
    }
}

希望这有助于某人,或至少给他们另一种选择。通常,恕我直言,我更愿意解析文件或流,但这只是我。