如何在 C# 中通过 ElementName 解析两个不同类中的 XML 字符串

问题描述 投票:0回答:1

我正在尝试将以下 XML 字符串解析为一个对象。它可以是“UpdateStructure”或“AddProcessLog”。基于类型我想把它解析成不同的对象。

这是一个显示 AddProcessLog 的 XML 示例:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Envelope>
  <Header>
    <Sender>MCTC</Sender>
    <MacAddress>00-0C-C6-86-E4-B2</MacAddress>
  </Header>
  <Body>
    <m:AddProcessLog xmlns:m="urn:mcsmart:machine" Version="2.1.0">
      <Machine Name="MC-TC Nick" Timestamp="1683621447526">
        <Active>false</Active>
        <ActLineSpeed>0.000</ActLineSpeed>
        <ActProductWeight>0.000</ActProductWeight>
        <EventCodes />
        <HasLineControl>false</HasLineControl>
        <InputType>Relay</InputType>
        <MaxEventType>None</MaxEventType>
        <OrderNumber />
        <ProductionMode>Extrusion</ProductionMode>
        <Recipe />
        <SetLineCapacity>-1.000</SetLineCapacity>
        <SetLineSpeed>0.125</SetLineSpeed>
        <SetProductWeight>1000.000</SetProductWeight>
        <ActTotalExtruderCapacity>0.000</ActTotalExtruderCapacity>
        <SetTotalExtruderCapacity>0.000</SetTotalExtruderCapacity>
        <Group Index="0" Name="Group1">
          <ActDosingTime>0.100</ActDosingTime>
          <SetDosingTime>0.100</SetDosingTime>
          <ActTachoVoltage>0.078</ActTachoVoltage>
          <SetTachoVoltage>24.000</SetTachoVoltage>
          <ShotWeight>0.100</ShotWeight>
          <ActExtruderCapacity>0.000</ActExtruderCapacity>
          <SetExtruderCapacity>0.028</SetExtruderCapacity>
          <ActExtruderSpeed>0.000</ActExtruderSpeed>
          <SetExtruderSpeed>0.000</SetExtruderSpeed>
          <ActWeightCapacity>0.000</ActWeightCapacity>
          <Consumption>0.000</Consumption>
          <EventCodes />
          <MaxEventType>None</MaxEventType>
          <Unit Index="0" Name="Unit1" Type="MCPowder">
            <ActMotorSpeed>0.000</ActMotorSpeed>
            <BatchCounter>0</BatchCounter>
            <BatchWeight>0.000</BatchWeight>
            <DosingMode>Gravimetric</DosingMode>
            <DosingTool>SP15</DosingTool>
            <EventCodes />
            <GrossWeight>0.000</GrossWeight>
            <MaxEventType>None</MaxEventType>
            <SetMotorSpeed>55.000</SetMotorSpeed>
            <Status>Off</Status>
            <Component Index="0" Name="Component1" Type="AdditiveV">
              <ActCapacity>0.000</ActCapacity>
              <ActDosingPercentage>0.000</ActDosingPercentage>
              <BandNumber>0</BandNumber>
              <Consumption>0.000</Consumption>
              <Material>sp15-ng</Material>
              <CorrectionFactor>1.000</CorrectionFactor>
              <EventCodes />
              <GranulateType>Normal</GranulateType>
              <MeasurementTime>0.000</MeasurementTime>
              <ActDosingWeight>0.000</ActDosingWeight>
              <SetDosingWeight>0.000</SetDosingWeight>
              <MaxEventType>None</MaxEventType>
              <PumpType>None</PumpType>
              <PumpSize>None</PumpSize>
              <RegrindFillLevel>0.000</RegrindFillLevel>
              <RegrindPercentage>0.000</RegrindPercentage>
              <SetCapacity>0.000</SetCapacity>
              <SetDosingPercentage>0.000</SetDosingPercentage>
              <Tolerance>25.000</Tolerance>
              <ValveType>None</ValveType>
            </Component>
          </Unit>
          <Unit Index="1" Name="Unit2" Type="MCBalance">
            <ActMotorSpeed>0.000</ActMotorSpeed>
            <BatchCounter>0</BatchCounter>
            <BatchWeight>0.000</BatchWeight>
            <DosingMode>Gravimetric</DosingMode>
            <DosingTool>GLX</DosingTool>
            <EventCodes />
            <GrossWeight>0.000</GrossWeight>
            <MaxEventType>None</MaxEventType>
            <SetMotorSpeed>0.000</SetMotorSpeed>
            <Status>Off</Status>
            <Component Index="0" Name="Component2" Type="AdditiveV">
              <ActCapacity>0.000</ActCapacity>
              <ActDosingPercentage>0.000</ActDosingPercentage>
              <BandNumber>0</BandNumber>
              <Consumption>0.000</Consumption>
              <Material>glx-ng</Material>
              <CorrectionFactor>1.000</CorrectionFactor>
              <EventCodes />
              <GranulateType>Normal</GranulateType>
              <MeasurementTime>432.900</MeasurementTime>
              <ActDosingWeight>0.000</ActDosingWeight>
              <SetDosingWeight>0.000</SetDosingWeight>
              <MaxEventType>None</MaxEventType>
              <PumpType>None</PumpType>
              <PumpSize>None</PumpSize>
              <RegrindFillLevel>0.000</RegrindFillLevel>
              <RegrindPercentage>0.000</RegrindPercentage>
              <SetCapacity>0.015</SetCapacity>
              <SetDosingPercentage>55.000</SetDosingPercentage>
              <Tolerance>25.000</Tolerance>
              <ValveType>None</ValveType>
            </Component>
          </Unit>
        </Group>
        <Group Index="1" Name="Group2">
          <ActDosingTime>0.100</ActDosingTime>
          <SetDosingTime>0.100</SetDosingTime>
          <ActTachoVoltage>0.000</ActTachoVoltage>
          <SetTachoVoltage>24.000</SetTachoVoltage>
          <ShotWeight>0.100</ShotWeight>
          <ActExtruderCapacity>0.000</ActExtruderCapacity>
          <SetExtruderCapacity>0.028</SetExtruderCapacity>
          <ActExtruderSpeed>0.000</ActExtruderSpeed>
          <SetExtruderSpeed>0.000</SetExtruderSpeed>
          <ActWeightCapacity>0.000</ActWeightCapacity>
          <Consumption>0.000</Consumption>
          <EventCodes />
          <MaxEventType>None</MaxEventType>
          <Unit Index="0" Name="Unit1" Type="MCBalance">
            <ActMotorSpeed>0.000</ActMotorSpeed>
            <BatchCounter>0</BatchCounter>
            <BatchWeight>0.000</BatchWeight>
            <DosingMode>Volumetric</DosingMode>
            <DosingTool>GLX</DosingTool>
            <EventCodes />
            <GrossWeight>0.000</GrossWeight>
            <MaxEventType>None</MaxEventType>
            <SetMotorSpeed>5.000</SetMotorSpeed>
            <Status>Off</Status>
            <Component Index="0" Name="Component1" Type="AdditiveV">
              <ActCapacity>0.000</ActCapacity>
              <ActDosingPercentage>0.000</ActDosingPercentage>
              <BandNumber>0</BandNumber>
              <Consumption>0.000</Consumption>
              <Material>glx-ng</Material>
              <CorrectionFactor>1.000</CorrectionFactor>
              <EventCodes />
              <GranulateType>Normal</GranulateType>
              <MeasurementTime>0.000</MeasurementTime>
              <ActDosingWeight>0.000</ActDosingWeight>
              <SetDosingWeight>0.000</SetDosingWeight>
              <MaxEventType>None</MaxEventType>
              <PumpType>None</PumpType>
              <PumpSize>None</PumpSize>
              <RegrindFillLevel>0.000</RegrindFillLevel>
              <RegrindPercentage>0.000</RegrindPercentage>
              <SetCapacity>0.000</SetCapacity>
              <SetDosingPercentage>100.000</SetDosingPercentage>
              <Tolerance>25.000</Tolerance>
              <ValveType>None</ValveType>
            </Component>
          </Unit>
          <Unit Index="1" Name="Unit2" Type="MCBalance">
            <ActMotorSpeed>0.000</ActMotorSpeed>
            <BatchCounter>0</BatchCounter>
            <BatchWeight>0.000</BatchWeight>
            <DosingMode>Gravimetric</DosingMode>
            <DosingTool>GLX</DosingTool>
            <EventCodes />
            <GrossWeight>0.000</GrossWeight>
            <MaxEventType>None</MaxEventType>
            <SetMotorSpeed>0.000</SetMotorSpeed>
            <Status>Off</Status>
            <Component Index="0" Name="Component2" Type="AdditiveV">
              <ActCapacity>0.000</ActCapacity>
              <ActDosingPercentage>0.000</ActDosingPercentage>
              <BandNumber>0</BandNumber>
              <Consumption>0.000</Consumption>
              <Material>glx-ng</Material>
              <CorrectionFactor>1.000</CorrectionFactor>
              <EventCodes />
              <GranulateType>Normal</GranulateType>
              <MeasurementTime>0.000</MeasurementTime>
              <ActDosingWeight>0.000</ActDosingWeight>
              <SetDosingWeight>0.000</SetDosingWeight>
              <MaxEventType>None</MaxEventType>
              <PumpType>None</PumpType>
              <PumpSize>None</PumpSize>
              <RegrindFillLevel>0.000</RegrindFillLevel>
              <RegrindPercentage>0.000</RegrindPercentage>
              <SetCapacity>0.000</SetCapacity>
              <SetDosingPercentage>10.000</SetDosingPercentage>
              <Tolerance>25.000</Tolerance>
              <ValveType>None</ValveType>
            </Component>
          </Unit>
        </Group>
      </Machine>
    </m:AddProcessLog>
  </Body>
</Envelope>

添加进程日志:

public class ProcessLog
{
    [XmlAttribute] 
    public string Version { get; set; }

    [XmlElement(Namespace = "", ElementName = "Machine")] 
    public MachineLog MachineLog { get; set; }
}

更新结构:

public class UpdateStructure
{
    [XmlAttribute] public string Version { get; set; }
    
    [XmlElement(Namespace = "", ElementName = "Machine" )] 
    public Machine Machine { get; set; }
}

现在我得到以下异常:

 ---> System.InvalidOperationException: There was an error reflecting property 'Body'.
 ---> System.InvalidOperationException: There was an error reflecting type 'MCSmart2.Shared.Models.CommunicationModels.Body'.
 ---> System.InvalidOperationException: There was an error reflecting property 'UpdateStructure'.
 ---> System.InvalidOperationException: There was an error reflecting type 'MCSmart2.Shared.Models.CommunicationModels.UpdateStructure'.
 ---> System.InvalidOperationException: There was an error reflecting property 'Machine'.
 ---> System.InvalidOperationException: The top XML element 'Machine' from namespace '' references distinct types MCSmart2.Shared.Models.CommunicationModels.MachineLog and MCSmart2.Shared.Models.CommunicationModels.Machine. Use XML attributes to specify another XML name or namespace for the element or types.
   at System.Xml.Serialization.XmlReflectionImporter.ReconcileAccessor(Accessor accessor, NameTable accessors)
   at System.Xml.Serialization.XmlReflectionImporter.ReconcileLocalAccessor(ElementAccessor accessor, String ns)
   at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at MCSmart.CommunicationModule.Parsers.XmlObjectParser`1.XmlToObject(Byte[] data) in C:\Users\NickdeBoerMovacolor\Movacolor\MCSmart\backend\MCSmart.CommunicationModule\Parsers\XmlObjectParser.cs:line 15
   at MCSmart.CommunicationModule.Communication.Connections.MctcConnection.MctcConnection.ReadDataAsync() in C:\Users\NickdeBoerMovacolor\Movacolor\MCSmart\backend\MCSmart.CommunicationModule\Communication\Connections\MctcConnection\MctcConnection.cs:line 72

有人知道我该如何解决这个问题吗?

c# xml serialization xmlserializer
1个回答
0
投票

您没有显示

<Body>
元素的完整架构,但从您的 c# 类来看,它似乎有一个 choice 架构,其中包含两个可能的子元素之一:

<Body>
    <m:AddProcessLog xmlns:m="urn:mcsmart:machine" Version="2.1.0">
        <!--Contents shown in question-->
    </m:AddProcessLog>
<Body>

<Body>
    <m:UpdateStructure xmlns:m="urn:mcsmart:machine" Version="2.1.0">
        <!--Contents not shown in question-->
    </m:UpdateStructure>
<Body>

假设这是正确的,您可以通过为

AddProcessLog
UpdateStructure
引入多态类型层次结构来绑定到这样的模式,如下所示:

public abstract class BodyValueBase
{
    [XmlAttribute] public string Version { get; set; }
}

[XmlRoot(ElementName="AddProcessLog", Namespace="")]
public class AddProcessLog : BodyValueBase
{
    [XmlElement(ElementName="Machine")]
    public MachineLog MachineLog { get; set; } // The type MachineLog is not shown in the question
}

[XmlRoot(ElementName="UpdateStructure", Namespace="")]
public class UpdateStructure : BodyValueBase
{
    [XmlElement(Namespace = "", ElementName = "Machine" )] 
    public Machine Machine { get; set; } // The type MachineLog is not shown in the question
}

然后对应于

<Envelope>
<Body>
<Header>
的根类应该如下所示:

[XmlRoot(ElementName="Body")]
public class Body 
{
    [XmlElement("AddProcessLog", typeof(AddProcessLog), Namespace="urn:mcsmart:machine")]
    [XmlElement("UpdateStructure", typeof(UpdateStructure), Namespace="urn:mcsmart:machine")]
    public BodyValueBase BodyValue { get; set; }
}

[XmlRoot(ElementName="Header")]
public class Header 
{
    [XmlElement(ElementName="Sender")]
    public string Sender { get; set; }
    [XmlElement(ElementName="MacAddress")]
    public string MacAddress { get; set; }
}

[XmlRoot(ElementName="Envelope")] // The type Envelope is not shown in the question
public class Envelope 
{
    [XmlElement(ElementName="Header")] // The type Header is not shown in the question
    public Header Header { get; set; }

    [XmlElement(ElementName="Body")]
    public Body Body { get; set; }
}

备注:

  1. 应该有多个

    [XmlElement(ElementName, Type, Namespace = namespace)]
    属性应用于
    Body.BodyValue
    ,一个用于
    BodyValueBase
    的每个多态子类型,其
    ElementName
    对应于适当的多态
    Type

  2. 有关将多态类型绑定到选择元素的文档,请参阅选择元素绑定支持:按类型区分

    另见这个答案Marc GravellUsing XmlSerializer to serialize derived classes有关

    XmlSerializer
    支持多态性的更多信息。

  3. 我将

    Version
    移到了基类,因为它似乎由两者共享。如果愿意,您可以将其删除并重新添加到两种派生类型中。

演示小提琴这里.

© www.soinside.com 2019 - 2024. All rights reserved.