在不修改C#XSD类的情况下,为XML序列化添加前缀和名称空间

时间:2018-03-23 14:49:17

标签: c# xml xsd xml-namespaces prefix

我们使用XSD文件published by Agresso 生成我们的XML文件。

我已经使用xsd.exe生成了XSD类,并且可以根据客户的要求成功生成XML文件。

命名空间区域看起来像

<ABWInvoice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:agrlib="http://services.agresso.com/schema/ABWSchemaLib/2011/11/14" xmlns="http://services.agresso.com/schema/ABWInvoice/2011/11/14">

我通过以下代码实现它:

public static string XmlNamespace<T>(T entity) where T: class
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true; //removing the encoding, e.g. instead of <?xml version="1.0" encoding="utf-16"?> should be <?xml version="1.0"?>

        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("agrlib", "http://services.agresso.com/schema/ABWSchemaLib/2011/11/14");
            ns.Add("xsi","http://www.w3.org/2001/XMLSchema-instance");

            XmlSerializer xser = new XmlSerializer(typeof(T));
            xser.Serialize(writer, entity, ns);
            return sw.ToString();
        }
    }

我们现在有一个客户,需要添加额外的前缀:“xsi:schemaLocation”,所以它将是

<ABWInvoice xsi:schemaLocation="http://services.agresso.com/schema/ABWInvoice/2011/11/14" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:agrlib="http://services.agresso.com/schema/ABWSchemaLib/2011/11/14" xmlns="http://services.agresso.com/schema/ABWInvoice/2011/11/14">

我在网上找到了很多示例,但它们都添加了 xmlns :schemaLocation而不是 xsi :schemaLocation。此外,我无法修改xsd类,因为它会影响其他客户。

因为我是C#的新手,可以建议如何处理这样的请求吗?

1 个答案:

答案 0 :(得分:1)

AFAIK,在代码中执行的唯一方法是添加以下内容:

public class YourRootType
{
    [XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string Bar {
        get => "http://services.agresso.com/schema/ABWInvoice/2011/11/14"; 
        set { }
    }
}

但这会影响所有实例。另一种方法可能是通过类似XSLT的方式添加值,但这很难看。如果您乐意将其保留在代码中,则可以使用条件序列化,即仅在设置时输出;例如:

[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Bar { get; set; }
// this pattern is recognized by the serializer itself
public bool ShouldSerializeBar() => !string.IsNullOrWhiteSpace(Bar);

并在运行时为这些客户端设置Bar"http://services.agresso.com/schema/ABWInvoice/2011/11/14"

另一种选择是使用[XmlAnyAttribute]

[XmlAnyAttribute]
XmlAttribute[] AdditionalAttributes { get; set; }

并在运行时附加任意附加属性。但这有点复杂,因为通过C#获取XmlAttribute实例有点尴尬 - 你需要创建一个DOM等。

我忘了说;在制作xsi:schemaLocation方面:XmlSerializerNamespaces所在的位置:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
ns.Add("agrlib", "http://services.agresso.com/schema/ABWSchemaLib/2011/11/14");
// etc

并将ns作为XmlSerializer.Serialize上的最后一个参数传递。