0

我正在尝试将 XML 反序列化为可用的对象图。我想让 XML 尽可能地人性化,因为在我们拥有能够在我们的系统中生成对象结构的工具之前还需要一段时间。

我正在寻找的是看起来像这样的 XML

<RuleSet>
  <Conditions>
    <AttributeEqualTo>
      <Id>C1</Id>
      <AttributeName>Foo</AttributeName>
      <ExpectedValue>Bar</ExpectedValue>
    </AttributeEqualTo>
    <AttributeNotEqualTo>
      <Id>C2</Id>
      <AttributeName>Blah</AttributeName>
      <ExpectedValue>Value</ExpectedValue>
    </AttributeNotEqualTo>
  </Conditions>
  <States>
    <State>
      <Id>Start</Id>
      <Transitions>
        <Transition>
            <Condition>C1</Condition>
            <State>S1</State>
        </Transition>
        <Transition>
            <Condition>C2</Condition>
            <State>S2</State>
        </Transition>
      </Transitions>
    </State>
    <State>
      <Id>S1</Id>
      <Transitions>
        <Transition>
            <Condition>C2</Condition>
            <State>S2</State>
        </Transition>
      </Transitions>
    </State>
    <State>
      <Id>S2</Id>
    </State>
  </States>
</RuleSet>

我正在寻找的是一个对象图,其中包含一个 RuleSet 对象,该对象具有一个可枚举的条件和一个可枚举的状态。每个状态将有一个可枚举的转换,这些转换由之前定义的条件、规则集的条件和另一个状态组成。

有没有一种简单的方法可以做到这一点,因为有人已经用 C# 编写了一个 XML 解析器,而不必编写我们自己的自定义解析器?

从最初的回答来看,我认为我需要增加一点清晰度。当我尝试序列化我们的对象图的一个简单版本时,打开维护引用的设置以减少重复。我收到以下信息:

<RuleSet z:Id="1" >
    <Conditions z:Id="2" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <a:anyType z:Id="3" i:type="b:AttributeEqualTo" >
            <b:AttributeName z:Id="4">Foo</b:AttributeName>
            <b:ExpectedValue z:Id="5" i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">Bar</b:ExpectedValue>
            <b:Id z:Id="6">C1</b:Id>
        </a:anyType>
        <a:anyType z:Id="7" i:type="b:AttributeEqualTo" >
            <b:AttributeName z:Ref="5" i:nil="true"/>
            <b:ExpectedValue z:Ref="4" i:nil="true"/>
            <b:Id z:Id="8">C2</b:Id>
        </a:anyType>
    </Conditions>
    <States z:Id="9" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <a:anyType z:Id="10" i:type="b:State" >
            <b:EntryActions z:Id="11"/>
            <b:Id z:Id="12">S1</b:Id>
            <b:Transitions z:Id="13" z:Size="2">
                <a:anyType z:Id="14" i:type="c:Transition" >
                    <c:Condition z:Ref="3" i:nil="true"/>
                    <c:Next z:Id="15" i:type="b:State">
                        <b:EntryActions z:Id="16"/>
                        <b:Id z:Id="17">S2</b:Id>
                        <b:Transitions z:Id="18" z:Size="1">
                            <a:anyType z:Id="19" i:type="c:Transition">
                                <c:Condition z:Ref="7" i:nil="true"/>
                                <c:Next z:Id="20" i:type="b:State">
                                    <b:EntryActions z:Id="21"/>
                                    <b:Id z:Id="22">S3</b:Id>
                                    <b:Transitions z:Id="23" z:Size="0"/>
                                </c:Next>
                            </a:anyType>
                        </b:Transitions>
                    </c:Next>
                </a:anyType>
                <a:anyType z:Id="24" i:type="c:Transition" >
                    <c:Condition z:Ref="7" i:nil="true"/>
                    <c:Next z:Ref="20" i:nil="true"/>
                </a:anyType>
            </b:Transitions>
        </a:anyType>
        <a:anyType z:Ref="15" i:nil="true"/>
        <a:anyType z:Ref="20" i:nil="true"/>
    </States>
</RuleSet>

我想要做的是将 z:Id="x" 和 z:Ref="x" 替换为我自己的 Id 属性的用法。再次使系统更具人类可写性。我看到了如何通过在 C# 类中设置属性来更改标签的名称。

4

3 回答 3

2

您不需要编写自己的解析器。您可以将 Xml 序列化属性应用于您的类,这将控制序列化和反序列化过程。或者您可以使用现有的解析器,例如 Linq to Xml。

下面是一个Xml 序列化属性使用的例子:

public class RuleSet
{
    [XmlArrayItem(typeof(AttributeEqualTo))]
    [XmlArrayItem(typeof(AttributeNotEqualTo))]
    public List<Condition> Conditions { get; set; }
}

public class Condition
{
    public string Id { get; set; }
    public string AttributeName { get; set; }
    public string ExpectedValue { get; set; }
}

public class AttributeEqualTo : Condition
{
    // code
}

public class AttributeNotEqualTo : Condition
{
    // code
}

和反序列化:

XmlSerializer serializer = new XmlSerializer(typeof(RuleSet));
RuleSet ruleSet = (RuleSet)serializer.Deserialize(stream_with_xml);

使用相同的方法来反序列化状态。

于 2013-01-16T15:42:31.190 回答
0

首先,要(反)序列化的对象是类或结构。您将需要一个 using 语句,包括 System.Xml 和 System.Xml.Serialization(在我的脑海中)。

然后你必须用 [Serializable] 属性装饰这个类/结构声明。如果您希望将其序列化为 XML 元素或 [XmlAttribute] 如果您希望将其序列化为您的序列化类的 XML 属性,请使用其相应的属性装饰您想要(反)序列化的每个公共属性和方法/结构。

还要确保你的类有一个无参数的构造函数,否则序列化将失败。

最后但同样重要的是,使用 XmlSerializer/XmlDeserializer 生成/解析。编写自定义 XML 解析的日子已经一去不复返了,这绝对是一个巨大的节省时间。

于 2013-01-16T15:56:10.353 回答
0

您可以为此使用XmlSerializer 。此外,假设您在所需的 XML 中没有任何 XML 属性,您还可以使用NetDataContractSerializer(DataContractSerializer 不支持发出属性 - 仅支持元素)。

无论哪种方式,您都可能需要使用属性(XmlAttributes 或 DataMember 属性)注释您的 C# 类,以使其根据需要精确序列化。

于 2013-01-16T15:48:54.897 回答