【问题标题】:Serialize object to XML without empty elements and elements with empty children将对象序列化为没有空元素和具有空子元素的 XML 的对象
【发布时间】:2015-12-11 10:22:44
【问题描述】:

我需要将对象序列化为 XML 请求,但我正在调用的服务不接受空元素。

我从 XSD 生成合约类,请求结构如下所示:

/* Generated contracts - simplified & without XML attributes */
public class Request
{
    public Request()
    {
        filters = new RequestFilters();
        properties = new ResultProperties();
    }

    public RequestFilters filters { get; set; }

    public ResultProperties properties { get; set; }
}

public class ResultProperties
{
    public ResultProperties()
    {
        props = new List<string>();
    }
    public List<string> props { get; set; }
}

public class RequestFilters
{
    public RequestFilters()
    {
        ids = new LongFilter();
        names = new StringFilter();
    }

    public LongFilter ids { get; set; }
    public StringFilter names { get; set; }
}

public class LongFilter
{
    public LongFilter()
    {
        values = new List<long>();
    }

    public List<long> values { get; set; }
}

public class StringFilter
{
    public StringFilter()
    {
        values = new List<string>();
    }

    public List<string> values { get; set; }
}

对于代码生成,我使用了 xsd2code 并将其配置为从序列化中排除空集合。创建对象时

Request request = new Request();

ResultProperties rp = new ResultProperties();
rp.props.Add("foo");
rp.props.Add("bar");

request.properties = rp;

我可以把它序列化成XML:

<?xml version="1.0" encoding="utf-16"?>
<Request xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <filters>
    <ids />
    <names />
  </filters>
  <properties>
    <props>
      <string>foo</string>
      <string>bar</string>
    </props>
  </properties>
</Request>

但是后端服务抱怨空的 &lt;ids /&gt;&lt;names /&gt; 元素。

是否有首选/任何方式从序列化 XML 中排除这些空元素?

如果我设法排除&lt;ids /&gt;&lt;names /&gt;,最终我也想摆脱&lt;filters&gt; 元素。谢谢。

更新:添加了 XSD 的相关部分

<xs:schema>
  <xs:element name="Request">
    <xs:complexType>
      <xs:sequence>             
        <xs:element name="filters" type="ouext:RequestFilters" minOccurs="0" />
        <xs:element name="properties" type="ouext:ResultProperties" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="RequestFilters">
      <xs:sequence>
        <xs:element name="ids" type="filters:LongFilter" minOccurs="0" />
        <xs:element name="names" type="filters:StringFilter" minOccurs="0" />
      <xs:sequence>
    </xs:complexType>

    <xs:complexType name="LongFilter">
      <xs:sequence>
        <xs:element name="values" type="filters:LongInFilter" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="LongInFilter">
      <xs:sequence>
        <xs:element name="value" type="xs:long" minOccurs="0" maxOccurs="20000" />
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="StringFilter">
      <xs:sequence>
        <xs:element name="values" type="filters:StringInFilter" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="StringInFilter">
      <xs:sequence>
        <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="20000" />
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="ResultProperties">
      <xs:sequence>
        <xs:element name="props" type="filters:StringInFilter" minOccurs="0" maxOccurs="unbounded">
        </xs:element>
      </xs:sequence>
    </xs:complexType>

  </xs:element>
</xs:schema>

更新:序列化如下

string xmlPayload = null;
XmlSerializer serializer = new XmlSerializer(typeof(Request));
using (StringWriter sw = new StringWriter())
{
    using (XmlWriter xw = XmlWriter.Create(sw))
    {
        serializer.Serialize(xw, payload); // payload is initialized object of Request type
        xmlPayload = sw.ToString();
    }
}

【问题讨论】:

  • xsd 长什么样子?
  • 您使用的是DataContractSerializer 还是XmlSerializer?您是在寻找手动执行此操作的方法,还是让 xsd2code 自动为您执行此操作的方法?
  • 我正在使用XmlSerializer,并希望使其尽可能自动化。

标签: c# .net xml serialization xsd2code


【解决方案1】:

我通过创建 InitMethods 解决了这个问题,它将未使用的字段和集合清空。

所以不要这样做

Request request = new Request();

ResultProperties rp = new ResultProperties();
rp.props.Add("foo");
rp.props.Add("bar");

request.properties = rp;

我在做

Request InitRequest(RequestFilters filters = null, ResultProperties properties = null)
{
     Request request = new Request();
     request.filters = filters;
     request.properties = properties;

     return request;
}

RequestFilters InitRequestFilters(LongFilter ids = null, StringFilter names = null)
{
     RequestFilters filters = new RequestFilters();
     filters.ids = ids;
     filters.names = names;
}

初始化ResultPropertiesLongFilterStringFilter 对象也是如此。

然后我使用InitMethods 创建请求:

List<string> properties = new List<string> { "foo", "bar" };
ResultProperties rp = InitResultProperties(properties);

Request request = InitRequest(properties: rp);

当我序列化request 时,我得到的只是包含实际值的 XML 元素,而序列化过程中省略了空元素:

<?xml version="1.0" encoding="utf-16"?>
<Request xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <properties>
    <props>
      <string>foo</string>
      <string>bar</string>
    </props>
  </properties>
</Request>

这不是最佳解决方案,因为创建 InitMethods 的开销很大,但我没有想出更好的解决方案。

【讨论】:

    猜你喜欢
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多