Choice and Inline Elements¶
Two XSD constructs produce class names that appear nowhere in the schema documentation: <choice> groups and elements declared inline inside their parent. This page shows how to recognize them and how to fill them.
Overview¶
| Construct | Generated class | Filled through |
|---|---|---|
<choice> group |
<Parent>_Choice |
add<Alternative>() or set<Alternative>(), then set<parent>_choice() on the parent |
| Inline element | <Parent>_Inline<Element> |
Its own accessors, like any other child class |
Choice groups¶
A choice group holds one of several alternatives. The generated method names follow the multiplicity declared in the schema.
| Method | Meaning |
|---|---|
contains<Alternative>() |
Whether a repeated alternative is present |
add<Alternative>(vector) |
Adds a vector of elements for a repeated alternative |
is<Alternative>() |
Whether an exclusive alternative is the one selected |
set<Alternative>(element) |
Selects an exclusive alternative, clearing the previous one |
Pixels shows the repeated form: its choice carries BinData, TiffData, NGFFData, and MetadataOnly children together. OME shows the exclusive form: a document is either a BinaryOnly reference to metadata stored elsewhere, or a full metadata document, never both.
In C++ the same construct is a std::variant. The Python binding exposes the methods above, so no visitor is needed.
Inline elements¶
Where the schema declares an element inside its parent instead of referencing a named type, the generator scopes a class to that parent. Screen declares Description and PlateRef inline, producing Screen_InlineDescription and Screen_InlinePlateRef. Only the class name differs: accessors, validation, and serialization behave as for named types, and the document carries the plain element name.
Note
Inline classes are not interchangeable between parents. Screen_InlinePlateRef describes the PlateRef of Screen alone, even though other parents declare an element of the same name.
Populate a choice group¶
The Pixels element below is exported without validation, because only its choice is populated. A validated export would ask for the ten attributes the schema requires on Pixels; Describe an Acquired Image sets them all.
import inscoper_nbo
# Step 1: A choice of repeated alternatives
# Pixels may carry BinData, TiffData, NGFFData, or MetadataOnly children. The
# choice object is filled first, then assigned to its parent.
pixels_choice = inscoper_nbo.Pixels_Choice()
print(pixels_choice.containsBinData(), pixels_choice.containsTiffData())
bin_data_list = inscoper_nbo.BinDataVector()
for compression in ("zlib", "bzip2"):
bin_data = inscoper_nbo.BinData()
bin_data.setCompression(compression)
bin_data.setBigEndian(True)
length = inscoper_nbo.NonNegativeLong_Type()
length.set(12)
bin_data.setLength(length)
bin_data_list.append(bin_data)
pixels_choice.addBinData(bin_data_list)
print(pixels_choice.containsBinData(), pixels_choice.containsTiffData())
pixels = inscoper_nbo.Pixels()
pixels.setpixels_choice(pixels_choice)
# Pixels declares required attributes of its own, which a validated export would
# demand. Only the choice matters here, so export without validation; see the
# Describe an Acquired Image example for a complete, valid Pixels element.
print(pixels.toXmlString(False))
# Step 2: A choice of exclusive alternatives
# OME holds either a BinaryOnly reference or a full metadata document. Setting
# one alternative clears the other.
ome_choice = inscoper_nbo.OME_Choice()
print(ome_choice.isBinaryOnly(), ome_choice.isOME_Choice_1())
binary_only = inscoper_nbo.OME_Choice_InlineBinaryOnly()
uuid = inscoper_nbo.UniversallyUniqueIdentifier_Type()
uuid.set("urn:uuid:3e450fae-b8f2-4d35-aa54-702168b2487f")
binary_only.setUUID(uuid)
binary_only.setMetadataFile("metadata.ome.xml")
ome_choice.setBinaryOnly(binary_only)
print(ome_choice.isBinaryOnly(), ome_choice.isOME_Choice_1())
full_document = inscoper_nbo.OME_Choice_InlineOME_Choice_1()
project = inscoper_nbo.Project()
project_id = inscoper_nbo.ProjectID_Type()
project_id.set("Project:1")
project.setID(project_id)
project.setName("Mitosis screen")
full_document.addToProject_List(project)
ome_choice.setOME_Choice_1(full_document)
print(ome_choice.isBinaryOnly(), ome_choice.isOME_Choice_1())
ome = inscoper_nbo.OME()
ome.setome_choice(ome_choice)
print(ome.toXmlString())
#include <NBO/NBO/BinData.h>
#include <NBO/NBO/NonNegativeLong_Type.h>
#include <NBO/NBO/OME.h>
#include <NBO/NBO/Pixels.h>
#include <NBO/NBO/Project.h>
#include <NBO/NBO/ProjectID_Type.h>
#include <NBO/NBO/UniversallyUniqueIdentifier_Type.h>
#include <iostream>
#include <memory>
#include <vector>
using namespace Inscoper;
int main() {
std::cout << std::boolalpha;
// Step 1: A choice of repeated alternatives
// Pixels may carry BinData, TiffData, NGFFData, or MetadataOnly children. The
// choice object is filled first, then assigned to its parent.
NBO::Pixels_ChoicePtr pixelsChoice = std::make_shared<NBO::Pixels_Choice>();
std::cout << pixelsChoice->containsBinData() << " " << pixelsChoice->containsTiffData()
<< std::endl;
std::vector<NBO::BinDataPtr> binDataList;
for (const std::string &compression : {"zlib", "bzip2"}) {
NBO::BinDataPtr binData = std::make_shared<NBO::BinData>();
binData->setCompression(compression);
binData->setBigEndian(true);
NBO::NonNegativeLong_TypePtr length = std::make_shared<NBO::NonNegativeLong_Type>();
length->set(12);
binData->setLength(length);
binDataList.push_back(binData);
}
pixelsChoice->addBinData(binDataList);
std::cout << pixelsChoice->containsBinData() << " " << pixelsChoice->containsTiffData()
<< std::endl;
NBO::Pixels pixels;
pixels.setpixels_choice(pixelsChoice);
// Pixels declares required attributes of its own, which a validated export would
// demand. Only the choice matters here, so export without validation; see the
// Describe an Acquired Image example for a complete, valid Pixels element.
std::cout << pixels.toXmlString(false) << std::endl;
// Step 2: A choice of exclusive alternatives
// OME holds either a BinaryOnly reference or a full metadata document. Setting
// one alternative clears the other. In C++ the choice is a std::variant, and the
// generated is / set helpers replace the need for a visitor.
NBO::OME_ChoicePtr omeChoice = std::make_shared<NBO::OME_Choice>();
std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;
NBO::OME_Choice::InlineBinaryOnlyPtr binaryOnly =
std::make_shared<NBO::OME_Choice::InlineBinaryOnly>();
NBO::UniversallyUniqueIdentifier_TypePtr uuid =
std::make_shared<NBO::UniversallyUniqueIdentifier_Type>();
uuid->set("urn:uuid:3e450fae-b8f2-4d35-aa54-702168b2487f");
binaryOnly->setUUID(uuid);
binaryOnly->setMetadataFile("metadata.ome.xml");
omeChoice->setBinaryOnly(binaryOnly);
std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;
NBO::OME_Choice::InlineOME_Choice_1Ptr fullDocument =
std::make_shared<NBO::OME_Choice::InlineOME_Choice_1>();
NBO::ProjectPtr project = std::make_shared<NBO::Project>();
NBO::ProjectID_TypePtr projectId = std::make_shared<NBO::ProjectID_Type>();
projectId->set("Project:1");
project->setID(projectId);
project->setName("Mitosis screen");
fullDocument->addToProject_List(project);
omeChoice->setOME_Choice_1(fullDocument);
std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;
NBO::OME ome;
ome.setome_choice(omeChoice);
std::cout << ome.toXmlString() << std::endl;
return 0;
}
import com.inscoper.nbo.BinData;
import com.inscoper.nbo.BinDataVector;
import com.inscoper.nbo.NonNegativeLong_Type;
import com.inscoper.nbo.OME;
import com.inscoper.nbo.OME_Choice;
import com.inscoper.nbo.OME_Choice_InlineBinaryOnly;
import com.inscoper.nbo.OME_Choice_InlineOME_Choice_1;
import com.inscoper.nbo.Pixels;
import com.inscoper.nbo.Pixels_Choice;
import com.inscoper.nbo.Project;
import com.inscoper.nbo.ProjectID_Type;
import com.inscoper.nbo.UniversallyUniqueIdentifier_Type;
public class ChoiceElements {
public static void main(String[] args) {
// Step 1: A choice of repeated alternatives
// Pixels may carry BinData, TiffData, NGFFData, or MetadataOnly children. The
// choice object is filled first, then assigned to its parent.
Pixels_Choice pixelsChoice = new Pixels_Choice();
System.out.println(pixelsChoice.containsBinData() + " " + pixelsChoice.containsTiffData());
BinDataVector binDataList = new BinDataVector();
for (String compression : new String[] {"zlib", "bzip2"}) {
BinData binData = new BinData();
binData.setCompression(compression);
binData.setBigEndian(true);
NonNegativeLong_Type length = new NonNegativeLong_Type();
length.set(12);
binData.setLength(length);
binDataList.add(binData);
}
pixelsChoice.addBinData(binDataList);
System.out.println(pixelsChoice.containsBinData() + " " + pixelsChoice.containsTiffData());
Pixels pixels = new Pixels();
pixels.setpixels_choice(pixelsChoice);
// Pixels declares required attributes of its own, which a validated export would
// demand. Only the choice matters here, so export without validation; see the
// Describe an Acquired Image example for a complete, valid Pixels element.
System.out.println(pixels.toXmlString(false));
// Step 2: A choice of exclusive alternatives
// OME holds either a BinaryOnly reference or a full metadata document. Setting
// one alternative clears the other.
OME_Choice omeChoice = new OME_Choice();
System.out.println(omeChoice.isBinaryOnly() + " " + omeChoice.isOME_Choice_1());
OME_Choice_InlineBinaryOnly binaryOnly = new OME_Choice_InlineBinaryOnly();
UniversallyUniqueIdentifier_Type uuid = new UniversallyUniqueIdentifier_Type();
uuid.set("urn:uuid:3e450fae-b8f2-4d35-aa54-702168b2487f");
binaryOnly.setUUID(uuid);
binaryOnly.setMetadataFile("metadata.ome.xml");
omeChoice.setBinaryOnly(binaryOnly);
System.out.println(omeChoice.isBinaryOnly() + " " + omeChoice.isOME_Choice_1());
OME_Choice_InlineOME_Choice_1 fullDocument = new OME_Choice_InlineOME_Choice_1();
Project project = new Project();
ProjectID_Type projectId = new ProjectID_Type();
projectId.set("Project:1");
project.setID(projectId);
project.setName("Mitosis screen");
fullDocument.addToProject_List(project);
omeChoice.setOME_Choice_1(fullDocument);
System.out.println(omeChoice.isBinaryOnly() + " " + omeChoice.isOME_Choice_1());
OME ome = new OME();
ome.setome_choice(omeChoice);
System.out.println(ome.toXmlString());
}
}
Populate inline elements¶
import inscoper_nbo
# Step 1: Recognize an inline type by its name
# An element declared inside Screen produces the class Screen_Inline<ElementName>,
# which exists only in the context of that parent.
screen = inscoper_nbo.Screen()
screen_id = inscoper_nbo.ScreenID_Type()
screen_id.set("Screen:1")
screen.setID(screen_id)
description = inscoper_nbo.Screen_InlineDescription()
description.set("Plate screen, 3 plates")
screen.setDescription(description)
# Step 2: Repeated inline elements behave like any other list
for plate in ("Plate:1", "Plate:2"):
plate_ref = inscoper_nbo.Screen_InlinePlateRef()
plate_id = inscoper_nbo.PlateID_Type()
plate_id.set(plate)
plate_ref.setID(plate_id)
screen.addToPlateRef_List(plate_ref)
print(screen.toXmlString())
# Step 3: Inline elements are read back from XML into the same classes
screen.fromXmlString(
"""<?xml version="1.0"?>
<Screen ID="Screen:03">
<Description>Rewritten from XML</Description>
<PlateRef ID="Plate:01" />
<PlateRef ID="Plate:02" />
<PlateRef ID="Plate:03" />
</Screen>"""
)
print(screen.getDescription().get())
print([plate_ref.getID().get() for plate_ref in screen.getPlateRef_List()])
#include <NBO/NBO/PlateID_Type.h>
#include <NBO/NBO/Screen.h>
#include <NBO/NBO/ScreenID_Type.h>
#include <iostream>
#include <memory>
using namespace Inscoper;
int main() {
// Step 1: Recognize an inline type by its name
// An element declared inside Screen produces the nested class
// Screen::Inline<ElementName>, which exists only in the context of that parent.
NBO::Screen screen;
NBO::ScreenID_TypePtr screenId = std::make_shared<NBO::ScreenID_Type>();
screenId->set("Screen:1");
screen.setID(screenId);
NBO::Screen::InlineDescriptionPtr description =
std::make_shared<NBO::Screen::InlineDescription>();
description->set("Plate screen, 3 plates");
screen.setDescription(description);
// Step 2: Repeated inline elements behave like any other list
for (const std::string &plate : {"Plate:1", "Plate:2"}) {
NBO::Screen::InlinePlateRefPtr plateRef = std::make_shared<NBO::Screen::InlinePlateRef>();
NBO::PlateID_TypePtr plateId = std::make_shared<NBO::PlateID_Type>();
plateId->set(plate);
plateRef->setID(plateId);
screen.addToPlateRef_List(plateRef);
}
std::cout << screen.toXmlString() << std::endl;
// Step 3: Inline elements are read back from XML into the same classes
screen.fromXmlString(R"(<?xml version="1.0"?>
<Screen ID="Screen:03">
<Description>Rewritten from XML</Description>
<PlateRef ID="Plate:01" />
<PlateRef ID="Plate:02" />
<PlateRef ID="Plate:03" />
</Screen>)");
std::cout << screen.getDescription()->get() << std::endl;
for (const auto &plateRef : screen.getPlateRef_List()) {
std::cout << plateRef->getID()->get() << " ";
}
std::cout << std::endl;
return 0;
}
import com.inscoper.nbo.PlateID_Type;
import com.inscoper.nbo.Screen;
import com.inscoper.nbo.ScreenID_Type;
import com.inscoper.nbo.Screen_InlineDescription;
import com.inscoper.nbo.Screen_InlinePlateRef;
public class InlineElements {
public static void main(String[] args) {
// Step 1: Recognize an inline type by its name
// An element declared inside Screen produces the class
// Screen_Inline<ElementName>, which exists only in the context of that parent.
Screen screen = new Screen();
ScreenID_Type screenId = new ScreenID_Type();
screenId.set("Screen:1");
screen.setID(screenId);
Screen_InlineDescription description = new Screen_InlineDescription();
description.set("Plate screen, 3 plates");
screen.setDescription(description);
// Step 2: Repeated inline elements behave like any other list
for (String plate : new String[] {"Plate:1", "Plate:2"}) {
Screen_InlinePlateRef plateRef = new Screen_InlinePlateRef();
PlateID_Type plateId = new PlateID_Type();
plateId.set(plate);
plateRef.setID(plateId);
screen.addToPlateRef_List(plateRef);
}
System.out.println(screen.toXmlString());
// Step 3: Inline elements are read back from XML into the same classes
screen.fromXmlString("""
<?xml version="1.0"?>
<Screen ID="Screen:03">
<Description>Rewritten from XML</Description>
<PlateRef ID="Plate:01" />
<PlateRef ID="Plate:02" />
<PlateRef ID="Plate:03" />
</Screen>""");
System.out.println(screen.getDescription().get());
for (Screen_InlinePlateRef plateRef : screen.getPlateRef_List()) {
System.out.print(plateRef.getID().get() + " ");
}
System.out.println();
}
}