如何使用 System.Xml.Schema 从 xs:choice 解析 xs:annotation

Posted

技术标签:

【中文标题】如何使用 System.Xml.Schema 从 xs:choice 解析 xs:annotation【英文标题】:How to parse xs:annotation from the xs:choice using the System.Xml.Schema 【发布时间】:2014-11-14 06:20:35 【问题描述】:

我正在尝试在 xs:choice 中添加注释元素。根据 xs:choice 语法,这是可能的。我在 BTW 中找不到带有注释的选择样本。我当前版本的 xsd 文件包含一个元素:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

    <xs:import namespace="http://www.es.de/es3/flex/flexBase" />

    <xs:element name="ESS3754">
        <xs:complexType>
            <xs:choice>
                <xs:annotation>
                    <xs:appinfo>
                        <flex:ControlHeadline>Headline_VVVVV</flex:ControlHeadline>
                        <flex:helpText>HelpText_VVVVV</flex:helpText>
                    </xs:appinfo>
                </xs:annotation>
                <xs:element name="String1" type="xs:string" minOccurs="1" maxOccurs="1"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>

</xs:schema>

但是,在解析 xsd 文件时,System.Xml.Schema.XmlSchemaChoice 对象的 Annotation 始终为空。

代码部分:

public List<FSBaseItem> Parse( XmlTextReader xsdReader )
        
            try
            
                // prepare schema set for schema validation and raw template xsd "enrichment"
                XmlSchemaSet schemaSet = new XmlSchemaSet();
                schemaSet.ValidationEventHandler += ValidationCallbackOne;

                // include base schema
                XmlSchema baseXsd = FlexXmlSchemaReader.ReadBase();
                schemaSet.Add( baseXsd );

                // The Read method will throw errors encountered on parsing the schema
                XmlSchema xsd = XmlSchema.Read( xsdReader, ValidationCallbackOne );
                schemaSet.Add( xsd );

                // The Compile method will throw errors encountered on compiling the schema
                schemaSet.Compile();

                // create root
                FSElement rootElement = new FSElement( this.GetNewId() );
                // traverse body
                this.TraverseSOM( xsd, rootElement );
                // validate
                this.ValidateFSItems( rootElement.Items );
                // init lists containers with minimum elements
                InitEmptyFEListItems( rootElement );                

                return rootElement.Items;
            
            finally
            
                xsdReader.Close();
            
        

在开始时,选择元素注释为空:(。有人可以提供一些工作示例或添加一些提示吗?任何帮助将不胜感激。

【问题讨论】:

如果你展示你的解析方式,你可能会得到更好的帮助。请提供显示问题的Minimal, Complete, and Verifiable Example (MCVE)。谢谢。 这个 xsd 是正确的,除了一件事。在 complexType 上缺少属性名称。 ..你能添加一个详细的例子吗? @Xstian,不,即使添加了 xs:complexType/@name 属性,XSD 也不正确(顺便说一句,我们不能确定是上下文 - 这可能是封闭 @987654326 的一部分@ 宣言)。 xs:schema 元素也丢失了,前缀“flex”和“xs”的命名空间定义也丢失了。 @kjhughes 我的意思是复杂类型是正确的......显然没有声明前缀。这只是一个例子,事实上我问是否可以添加更多细节。 @kjhughes:帖子已更新,包含完整的 xsd 和解析实现。 【参考方案1】:

注释当然可以放在 xs:choice 中。看下面的xsd取自Inline Annotated Schema

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
  jaxb:version="1.0" jaxb:extensionBindingPrefixes="xjc">
    <xs:annotation>
        <xs:appinfo>
            <jaxb:globalBindings>
                <xjc:superClass name="com.syh.Shape"/>
            </jaxb:globalBindings>
        </xs:appinfo>
    </xs:annotation>
    <xs:element name="Widgets">
        <xs:complexType>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:annotation>
                    <xs:appinfo>
                        <jaxb:property name="Shapes"/>
                    </xs:appinfo>
                </xs:annotation>
                <xs:element name="Rectangle" type="Rectangle"/>
                <xs:element name="Square" type="Square"/>
                <xs:element name="Circle" type="Circle"/>
            </xs:choice>
         </xs:complexType>
    </xs:element>
    <xs:complexType name="Rectangle">
        <xs:sequence>
            <xs:element name="Width" type="xs:integer"/>
            <xs:element name="Height" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Square">
        <xs:sequence>
            <xs:element name="Length" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Circle">
        <xs:sequence>
            <xs:element name="Radius" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

为您的 xsd 调整类似的策略会产生如下结果:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />

  <xs:element name="ESS3754">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:annotation>
          <xs:appinfo>
            <flex:ControlHeadline>Headline_VVVVV</flex:ControlHeadline>
            <flex:helpText>HelpText_VVVVV</flex:helpText>
          </xs:appinfo>
        </xs:annotation>
        <xs:element name="String1" type="xs:string" minOccurs="1" maxOccurs="10"/>
        <xs:element name="NewlyAdded" type="Coordinate" minOccurs="1" maxOccurs="10"/>
      </xs:choice>
    </xs:complexType>    
  </xs:element>
  <xs:complexType name="Coordinate">
  <xs:sequence>
    <xs:element name="LocationX" type="xs:integer"/>
    <xs:element name="LocationY" type="xs:integer"/>
    <xs:element name="LocationZ" type="xs:integer"/>
  </xs:sequence>
</xs:complexType>    

</xs:schema>

xsd 完全有效,在 Visual Studio [XSD] Desginer 中如下所示:

更新 1

我同意调试器将项目注释显示为 null [我也找不到但我应该找到它] 的事实,这非常令人沮丧。我使用代码重建了文档,您可以使用以下解决方法注释您的元素: 考虑以下 XSD,它没有任何 XmlSchemaChoice 并保存为 stack-problem2.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />




  <xs:complexType name="Coordinate">
    <xs:sequence>
      <xs:element name="LocationX" type="xs:integer"/>
      <xs:element name="LocationY" type="xs:integer"/>
      <xs:element name="LocationZ" type="xs:integer"/>
    </xs:sequence>
  </xs:complexType>  
</xs:schema>

现在您可以将其加载到内存中并以编程方式将注释添加到 XmlSchemaChoice 元素:

public void Parse()

    try
    
        XmlTextReader reader2 = new XmlTextReader(@"stack-problem2.xsd");
        XmlSchema myschema2 = XmlSchema.Read(reader2, ValidationCallback);


        var simpleAnotation = new XmlSchemaAnnotation();
        simpleAnotation.Id = "Lost Anotation";

        // <xs:complexType name="ESS3754">
        XmlSchemaComplexType complexType = new XmlSchemaComplexType();
        myschema2.Items.Add(complexType);
        complexType.Name = "ESS3754";

        // <xs:choice minOccurs="1" maxOccurs="1">
        XmlSchemaChoice choice = new XmlSchemaChoice();
        complexType.Particle = choice;
        choice.MinOccurs = 1;
        choice.MaxOccurs = 1;

        XmlSchemaElement elementSelected = new XmlSchemaElement();
        choice.Items.Add(elementSelected);
        elementSelected.Name = "String1";

        AnnonateMyComplexType(choice); 

        FileStream file = new FileStream(@"satck-solution.xsd", FileMode.Create, FileAccess.ReadWrite);
        XmlTextWriter xwriter = new XmlTextWriter(file, new UTF8Encoding());
        xwriter.Formatting = Formatting.Indented;
        myschema2.Write(xwriter);
    
    catch (Exception e)
    
        Console.WriteLine(e);
    


public static void AnnonateMyComplexType(XmlSchemaChoice xmlSchemaComplexType)


    XmlSchemaAnnotation myCustomAnnotation = new XmlSchemaAnnotation();
    xmlSchemaComplexType.Annotation = myCustomAnnotation;

    // <xs:documentation>State Name</xs:documentation>
    XmlSchemaDocumentation schemaDocumentation = new XmlSchemaDocumentation();
    myCustomAnnotation.Items.Add(schemaDocumentation);
    schemaDocumentation.Markup = TextToNodeArray("Headline_VVVVV");

    // <xs:appInfo>Application Information</xs:appInfo>
    XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo();
    myCustomAnnotation.Items.Add(appInfo);
    appInfo.Markup = TextToNodeArray("Headline_VVVVV");



static void ValidationCallback(object sender, ValidationEventArgs args)

    if (args.Severity == XmlSeverityType.Warning)
        Console.Write("WARNING: ");
    else if (args.Severity == XmlSeverityType.Error)
        Console.Write("ERROR: ");

    Console.WriteLine(args.Message);

上面运行会返回以下XSD文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://www.es.de/es3/flex/simple" xmlns:flex="http://www.es.de/es3/flex/flexBase" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" targetNamespace="http://www.es.de/es3/flex/simple" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />
  <xs:complexType name="Coordinate">
    <xs:sequence>
      <xs:element name="LocationX" type="xs:integer" />
      <xs:element name="LocationY" type="xs:integer" />
      <xs:element name="LocationZ" type="xs:integer" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ESS3754">
    <xs:choice minOccurs="1" maxOccurs="1">
      <xs:annotation>
        <xs:documentation>Headline_VVVVV</xs:documentation>
        <xs:appinfo>Headline_VVVVV</xs:appinfo>
      </xs:annotation>
      <xs:element name="String1" />
    </xs:choice>
  </xs:complexType>
</xs:schema>

所以回答你的第一个问题:是的,注释肯定可以放在 XmlSchemaChoice 元素中(通过代码和直接)[不一定在 xmlSchemaChoice 之外作为顶部元素,根据你的实验]并解决你的第二个问题:[我和你有类似的经历!它将注释显示为 null,尽管它不是]

【讨论】:

但是,我仍然无法解析它。在这种情况下,System.Xml.Schema.XmlSchemaComplexType 具有属性“ContentTypeParticle”,其类型为 System.Xml.Schema.XmlSchemaChoice,但选择的 Annotation 一如既往为空。你可以尝试使用 XmlSchema.Read(..) 你会看到。 Schema 本身是正确的,但是 Annotation 元素是一种例外,而且有点令人困惑。请阅读msdn.microsoft.com/en-us/library/ms950785.aspx 和***.com/questions/8400185/… 提问者有与你类似的问题。 @MHOOS,非常有帮助。我建议您将 MSDN 链接的摘录添加到您的答案中,因为它可能包含 OP 问题的本质,而不是 XSD 是否允许选择注释(它显然是这样做的)。 @MHOOS 是的,在架构级别它可以工作,但在 xs:choice 级别它不会。 我更新了我的答案并添加了一些解决方法。希望对您有所帮助。【参考方案2】:

对于遇到此问题的其他人,我通过反映 System.Xml.Schema 命名空间的类发现,在编译模式集时,元素的注释会复制到它们的子级。

因此,Vytas999 应该能够(正如我已经能够)通过检查 XmlSchemaChoice.Items 属性中的 XmlSchemaParticle 对象来找到他丢失的注释。

【讨论】:

【参考方案3】:

我遇到了同样的问题 - 我需要处理外部实体提供的 XSD,而 XmlSchemaChoiceAnnotation 始终为空。

详细说明@Adrian 的答案,我成功使用的代码如下。在我的例子中,我从根向下遍历模式,当我点击XmlSchemaSequence 时,我遍历它的 Items 集合:

var index = 0;
foreach (var childObject in sequence.Items)

    ExtractElement(childObject, index);
    ++index ;

当 childObject 的类型为 XmlSchemaChoice 时(假设它在变量 xmlSchemaChoice 中,则不是

// DOES NOT WORK - always null
var choiceAnnotation = xmlSchemaChoice.Annotation

我像这样访问注释:

((xmlSchemaChoice.Parent as XmlSchemaSequence)?.Items[index] as XmlSchemaChoice)?.Annotation

你会期待同样的结果吗?好吧,它不是..

此代码只是描述通过父项访问注释的示例 sn-p,它不是通用代码,可能需要根据您的具体情况进行一些调整。

【讨论】:

以上是关于如何使用 System.Xml.Schema 从 xs:choice 解析 xs:annotation的主要内容,如果未能解决你的问题,请参考以下文章

如何使用颤振提供程序从 Firestore 获取数据?

如何使用 oauth 从用户那里获取详细信息? [关闭]

如何从命令行(使用 kotlinc)使用 kapt?

如何使用 SWIG 从 C 调用 C# 方法?

如何从 python 使用 mongolab 插件到 Heroku?

如何从 python 使用 mongolab 插件到 Heroku?