ISO 19115-3 metadata

For each metadata class, there is an XML type with the same name than in the abstract specification (for example, mdb:MD_Metadata and cit:CI_Citation). All of these types may be used as the root of an XML document. It is therefore possible to write a document representing a complete MD_Metadata object, or to write a document representing only a CI_Citation object.

ISO 19115-3 standard arranges the content of these objects in an unusual way: for each property whose value type is itself another class of ISO 19115, the value is wrapped in an element that represents its type, rather than being written directly. For example, in an object of the CI_Citation type, the value of the citedResponsibleParty property is incorporated into a CI_Responsibility element. This practice doubles the depth of the hierarchy, and introduces duplication at all levels for each value, as in the following example:

<MD_Metadata>
  <identificationInfo>
    <MD_DataIdentification>
      <citation>
        <CI_Citation>
          <citedResponsibleParty>
            <CI_Responsibility>
              <party>
                <CI_Party>
                  <contactInfo>
                    <CI_Contact>
                      <onlineResource>
                        <CI_OnlineResource>
                          <linkage>
                            <URL>https://www.ogc.org</URL>
                          </linkage>
                        </CI_OnlineResource>
                      </onlineResource>
                    </CI_Contact>
                  </contactInfo>
                </CI_Party>
              </party>
            </CI_Responsibility>
          </citedResponsibleParty>
        </CI_Citation>
      </citation>
    </MD_DataIdentification>
  </identificationInfo>
</MD_Metadata>

The preceding example, like all documents that conform to ISO 19115-3, consists of a systematic alternation of two types of XML elements:

  1. It begins with the name of the property, which always begins with a lower-case letter (ignoring prefixes). In Java APIs, each property corresponds to a method in its enclosing class. In the example above, mdb:identificationInfo (a property of MD_Metadata class) corresponds to the Metadata.getIdentificationInfo() method.

  2. The value type is included under each property, unless it has been replaced with a reference (the following sub-section will elaborate on this subject). The value type is an XML element whose name always begins with an upper-case letter, ignoring prefixes. In the example above we had MD_DataIdentification, which corresponds to the DataIdentification Java interface. It is this XML element that contains the child properties.

In order to reduce the complexity of the libraries, GeoAPI and Apache SIS only expose publicly a single unified view of these two types of elements. The public API basically corresponds to the second group.

Links to previously-defined instances

The parent element may contain an id or uuid attribute. If one of these attributes is present, the parent attribute may be completely omitted; it will be replaced at the time of reading by the element referenced by the attribute. In the following example, the part on the left defines an element associated with the identifier “my_id,” while the part on the right references this element:

Defining an identifier
<MD_MetaData>
  <identificationInfo>
    <MD_DataIdentification id="my_id">
      <!-- insert child properties here -->
    </MD_DataIdentification>
  </identificationInfo>
</MD_MetaData>
Using a defined identifier
<MD_MetaData>
  <identificationInfo xlink:href="#my_id"/>
</MD_MetaData>

The decision of which attribute to use depends on the scope of the referenced item:

In the SIS library, all objects that can be identified in an XML document implements the org.apache.sis.xml.IdentifiedObject interface. Each instance of this interface provides a view of its identifiers in the form of a Map<Citation,String>, in which the Citation key indicates the type of identifier and the value is the identifier itself. Some constants representing different types of identifiers are listed in IdentifierSpace, including ID, UUID and HREF. Each of these keys may be associated with a different type of value (usually String, UUID or URI) depending on the key. For example, the following code defines a value for the uuid attribute:

import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.xml.IdentifierSpace;
import java.util.UUID;

public class MyClass {
    public void myMethod() {
        UUID identifier = UUID.randomUUID();
        DefaultMetadata metadata = new DefaultMetadata();
        metadata.getIdentifierMap().putSpecialized(IdentifierSpace.UUID, identifier);
    }
}

Although this mechanism has been defined in order to better support the representation of XML attributes of the gco:ObjectIdentification group, it also conveniently allows other types of identifiers to be manipulated. For example, the ISBN and ISSN attributes of Citation may be manipulated in this way. The methods of the IdentifiedObject interface therefore provides a specific location where all types of identifiers (not only XML) associated with an object may be manipulated.

Placeholders for missing values

When a property is not defined, the corresponding GeoAPI method usually returns null. However, things become complicated when the missing property is a value considered mandatory by ISO 19115 standard. ISO 19115-3 allows for the omission of mandatory properties so long as the reason for the missing value is indicated. The reason may be that the property is not applicable (inapplicable), that the value probably exists but is not known (unknown), that the value cannot exist (missing), or that the value cannot be revealed (withheld), etc. The transmission of this information requires the use of a non-nul object, even when the value is missing. SIS will then return an object that, besides implementing the desired GeoAPI interface, also implements the org.apache.sis.xml.NilObject interface. This interface flags the instances where all methods return an empty collection, an empty table, null, NaN, 0 or false, in this preference order, as permitted by the return types of the methods. Each instance that implements NilObject provides a getNilReason() method indicating why the object is nil.

In the following example, the left side shows a CI_Citation element containing a CI_Series element, while on the right side the series is unknown. If the CI_Series element had been completely omitted, then the Citation.getSeries() method would return null in Java. But when a nilReason is present, the SIS implementation of getSeries() returns instead an object that implements both the Series and NilReason interfaces, and in which the getNilReason() method returns the constant UNKNOWN.

Information included
<CI_Citation>
  <series>
    <CI_Series>
      <!-- insert child properties here -->
    </CI_Series>
  </series>
</CI_Citation>
Missing information
<CI_Citation>
  <series nilReason="unknown"/>
</CI_Citation>