【问题标题】:How to use Complex types with xs:any / ##any and mixed in code generated by the XSD tool如何在 xs:any / ##any 中使用复杂类型并混合在 XSD 工具生成的代码中
【发布时间】:2011-06-25 13:25:33
【问题描述】:

我的 XML 架构中有以下复杂类型:

<xs:complexType name="Widget" mixed="true">
    <xs:sequence>
        <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

派生 XML 中的元素可能包含字符串或格式正确的 XML,因此混合属性为 true。

当我通过 .NET XSD 工具运行它时,我得到以下生成代码:

public partial class Widget{

    private System.Xml.XmlNode[] anyField;

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    [System.Xml.Serialization.XmlAnyElementAttribute()]
    public System.Xml.XmlNode[] Any {
        get {
            return this.anyField;
        }
        set {
            this.anyField = value;
        }
    }
}

我的问题是我不完全确定我应该如何使用它。最终我需要能够将小部件的值设置为:

<widget>Hello World!</widget>

<widget>
  <foo>Hello World</foo>
</widget>

两者都针对架构进行验证

【问题讨论】:

    标签: c# xml-serialization xsd xmlnode


    【解决方案1】:

    为此:

    <widget>  
        <foo>Hello World</foo>
    </widget>
    

    使用这个:

    XmlDocument dom = new XmlDocument();
    Widget xmlWidget = new Widget();
    xmlWidget.Any = new XmlNode[1];
    xmlWidget.Any[0] = dom.CreateNode(XmlNodeType.Element, "foo", dom.NamespaceURI);
    xmlWidget.Any[0].InnerText = "Hello World!";
    

    为此:

    <widget>Hello World!</widget>
    

    使用这个:

    XmlDocument dom = new XmlDocument();
    XmlNode node = dom.CreateNode(XmlNodeType.Element, "foo", dom.NamespaceURI);
    node.InnerText = "Hello World";
    
    Widget w = new Widget();
    w.Any = new XmlNode[1];
    w.Any[0] = node.FirstChild; 
    

    【讨论】:

    • 那不行,你还没有初始化 xmlWidget.Any[0]。所以它会抛出一个空引用异常
    • 我更新了我的答案以处理 NullReferenceExceptions。但是,我不确定您是否能够完成“仅内部文本”选项。在代码中执行此操作意味着 Widget 类既可以用作字符串类型,也可以用作节点数组。我不相信这在标准 XSD 生成中是可能的。
    • 我做了一个与您发布的代码非常相似的编辑。我不确定你是否会找到一种不同的方法来做到这一点。实际上,您正在尝试覆盖 Widget 属性。在一种情况下,您希望它只是一个字符串,而在其他情况下,您需要一个节点数组,但您不能在一个类中多次定义同名的属性。
    • 为了更明确(​​并显示代码的意图),您可以将调用 node.FirstChild 替换为 dom.CreateTextNode("Hello World")。
    【解决方案2】:

    将此作为答案发布,因为它在技术上有效并回答了问题。然而,这似乎是一个非常讨厌的黑客攻击。因此,如果有人有其他更好的解决方案,我会全力以赴。

    string mystring= "if I check this code in it will at least have comedy value";
    
    XmlDocument thisLooksBad = new XmlDocument();
    thisLooksBad.LoadXml("<temp>" + mystring + "</temp>");
    
    Widget stringWidget = new Widget();
    stringWidget.Any = new XmlNode[1];
    stringWidget.Any[0] = thisLooksBad.SelectSingleNode("/temp").FirstChild;
    

    如您所见,我将字符串放入包含在标签中的 XmlDocument 中,这可以正常工作、编译和序列化 - 所以是的,这是一个解决方案,但让我觉得这是一个讨厌的 hack。

    string myxml = "<x><y>something</y></x>";
    
    XmlDocument thisDoesntLookSoBad = new XmlDocument();
    thisLooksBad.LoadXml(myxml);
    
    Widget xmlWidget = new Widget();
    xmlWidget.Any = new XmlNode[1];
    xmlWidget.Any[0] = thisDoesntLookSoBad;
    

    在本例中,我将 XML 放入 XmlDocument 中,然后将其分配给生成的类。这更有意义,因为我使用的是 XML 而不是原始字符串。

    奇怪的是,我也可以这样做,而且效果也很好(但也是一个讨厌的 hack):

    string myxml = "<x><y>something</y></x>";
    
    XmlDocument dom = new XmlDocument();
    dom.LoadXml("<temp>" + myxml + "</temp>");
    
    Widget xmlWidget = new Widget();
    xmlWidget.Any = new XmlNode[1];
    xmlWidget.Any[0] = dom.SelectSingleNode("/temp").FirstChild;
    

    【讨论】:

    • 这些示例中哪一个满足&lt;widget&gt;Hello World!&lt;/widget&gt; 要求。
    • 第一个示例反序列化为:如果我在其中检查此代码,至少会有喜剧价值
    • 就像你说的,这可以完成工作,但我更喜欢 pmartin 的解决方案,因为它更健壮,即不使用字符串连接来构建 Xml DOM。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    相关资源
    最近更新 更多