verisimilitude
verisimilitude

Reputation: 5108

Unable to extend XML complex types with the parent type in a namespace

I am facing an issue while trying to extend a complex type from an XSD. The crux is this - the complex type I'm trying to implement is in a namespace and this same namespace is set as the targetNamespace of the parent.

Here is the parent XSD (relevant portion)

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.mandiant.com/2010/ioc" 
           elementFormDefault="qualified" 
           targetNamespace="http://schemas.mandiant.com/2010/ioc" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ioc" nillable="true" 
              type="tns:IndicatorOfCompromise" />
  <xs:complexType name="IndicatorOfCompromise">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="short_description" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="description" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="keywords" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="authored_by" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" 
                  name="authored_date" nillable="true" 
                  type="xs:dateTime" />
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="links" type="tns:ArrayOfLink" />
      <xs:element minOccurs="0" maxOccurs="1" 
                  name="definition" type="tns:ArrayOfIocIndicator" />
    </xs:sequence>
    <xs:attribute name="id" type="xs:string" />
    <xs:attribute name="last-modified" type="xs:dateTime" 
                  use="required" />
  </xs:complexType>
</xs:schema>

This is how I'm trying to extend (basically add few more elements to) it

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           targetNamespace="http://schemas.mandiant.com/2010/ioc" >
    <xs:import namespace="urn:tns" 
               schemaLocation="openioc_schema_v10.xsd" />
    <xs:redefine schemaLocation="openioc_schema_v10.xsd">
      <xs:complexType name="IndicatorOfCompromise">
        <xs:complexContent>
          <xs:extension base="tns:IndicatorOfCompromise">
            <xs:sequence>
                <xs:element name="category" type="xs:string" />
                <xs:element name="family" type="xs:string" />
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    </xs:redefine>
</xs:schema>

When I try to validate the below XML against this schema,

<?xml version='1.0' encoding='UTF-8'?>
<ioc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
     xmlns="http://schemas.mandiant.com/2010/ioc" 
     id="2555192b-186b-441d-bbdd-1d2fb41f462f" 
     last-modified="2016-05-12T12:14:50"
     xmlns:qioc_v10="ioc_qualys_v10.xsd" 
     xsi:schemaLocation="ioc_qualys_v10.xsd">
  <short_description>Bagsu!rfn</short_description>
  <description>This is a placeholder for description of the Bagsu!rfn malware family.</description>
  <keywords/>
  <authored_by>IOC_api</authored_by>
  <authored_date>2016-05-12T12:14:50</authored_date>
  <qioc_v10:category>XYZ</qioc_v10:category>
  <qioc_v10:family>XYZ 2</qioc_v10:family>
  <links/>
</ioc>

it gives an error "The namespace attribute, 'urn:tns', of an element information item must be identical to the targetNamespace attribute, 'http://schemas.mandiant.com/2010/ioc', of the imported document."

How to go about it? I have gone through several Stackoverflow posts on this but none seem to resolve my conundrum. I've understood the problem that the element I need to extend resides in a namespace but not getting what to do to fix it.

Please note that I cannot touch the parent xsd in any way. It's the OpenIOC standard.

Upvotes: 1

Views: 686

Answers (1)

C. M. Sperberg-McQueen
C. M. Sperberg-McQueen

Reputation: 25054

You probably want to read up on the basics of XSD import, include, redefine, and (for XSD 1.1) override. That will reduce the amount of guessing you have to do.

In this case, your local modification has several problems, all related to your having to guess what to do instead of having a clear understanding of what inter-schema-document references mean.

  1. First, the import statement is incompatible with the schema document you are suggesting for import. The local schema you show has:

    <xs:import namespace="urn:tns" 
           schemaLocation="openioc_schema_v10.xsd" />
    

    which means "the components declared here may refer to schema components for namespace urn:tns; a schema document for that namespace can be found at openioc_schema_v10.xsd." But if the schema processor accepts your hint and tries to read openioc_schema_v10.xsd, it finds that its target namespace is http://schemas.mandiant.com/2010/ioc, not urn:tns. It cannot possibly declare any components for namespace urn:tns, so it cannot usefully be named in the schemaLocation attribute of an import for namespace urn:tns.

  2. You can fix this, of course, by specifying the correct namespace on the import statement:

    <xs:import namespace="http://schemas.mandiant.com/2010/ioc" 
           schemaLocation="openioc_schema_v10.xsd" />
    

    If you do this, you will get a new and different error message, because you are trying to import a schema for your target namespace. Just as "import" in ordinary English means the introduction of foreign goods into a domestic market, so "import" in XSD means the introduction of schema components from other (foreign) namespaces. You cannot import a schema for your target namespace. That's what xsd:include is for.

  3. If you change the import to an include, you may or may not get a schema that raises error messages, but you won't get a schema that works reliably across implementations, because now you are both including the (unchanged) version of openioc_schema_v10.xsd (via include) and including a modified version of it (via redefine).

    You are better off eliminating the import-which-should-be-an-include entirely. The redefinition of the schema defined at openioc_schema_v10.xsd will bring in all of the schema components of that schema, with the modifications specified by your redefinition.

  4. If you delete the erroneous and unnecessary import, you will find that your declaration of the type IndicatorOfCompromise specifies a base type of tns:IndicatorOfCompromise, but nowwhere in your schema document do you bind the namespace prefix tns to any namespace. You want

    xmlns:tns="http://schemas.mandiant.com/2010/ioc"
    

on the xs:extension element or an ancestor.

These are the mechanical problems that are visible at first glance; there may be more. As I say: find a good tutorial, read it, learn the basics of include, import, redefine, and override.

One other thing: If you are extending a publicly defined type, it is possible, perhaps likely, that you should be defining the new type in a namespace of your own, and not by redefining the type in a namespace owned by someone else. But that would take us too far afield. Good luck.

Upvotes: 3

Related Questions