Export and Import NBO-XML¶
NBO-XML is the exchange format of the model. Any element of the tree can be written to XML and read back, so serialization starts from whatever you hold: a whole OME document, one Instrument, or a single Objective.
Overview¶
| Method | Description |
|---|---|
toXmlString() |
Returns the element and its content as an XML string |
toXmlFile(path) |
Writes the element and its content to a file |
fromXmlString(xml) |
Replaces the content of the element with that of an XML string |
fromXmlFile(path) |
Replaces the content of the element with that of an XML file |
Import replaces rather than merges: whatever the element held is discarded, which makes repeated imports into the same object safe.
All four methods take a trailing validate argument, True by default, covering three things.
| Checked | With validate=True |
With validate=False |
|---|---|---|
| Restricted values | A value violating an enumeration, a pattern, or a range raises InscoperNBOValidationException |
The value is written or stored as it is |
| Required attributes | An element missing a required attribute raises on export | The element is written without it |
| Schema defaults | Attributes carrying a default are written explicitly | Only the attributes set are written |
Required attributes surprise most often, because the schema asks for more than it seems: twelve on Objective, seven on Detector. A validated export is therefore also a compliance check. Disable validation only to serialize an incomplete draft, or to pass through data from a non-compliant source.
Note
The import example reads instrument_sample.xml. Download it below, or point SAMPLE_PATH at an NBO-XML document of your own.
Export to XML¶
BinData shows what validation adds to the output: its Compression attribute defaults to none in the schema, so a validated export writes it and an unvalidated one omits it.
import os
import tempfile
import inscoper_nbo
# Build a small tree: an image carrying three stage positions
image = inscoper_nbo.Image()
image_id = inscoper_nbo.ImageID_Type()
image_id.set("Image:1")
image.setID(image_id)
name = inscoper_nbo.Denomination_Type()
name.set("Field 1")
image.setName(name)
for index, (x, y) in enumerate([(0.0, 0.0), (120.5, 0.0), (241.0, 0.0)]):
stage_label = inscoper_nbo.StageLabel()
stage_label.setName(f"Position {index}")
stage_label.setX(x)
stage_label.setY(y)
image.addToStageLabel_List(stage_label)
# Step 1: Serialize to a string
print(image.toXmlString())
# Step 2: Serialize to a file
output_path = os.path.join(tempfile.gettempdir(), "image.xml")
image.toXmlFile(output_path)
print(f"Written to {output_path}")
# Step 3: Control validation on export
# Export validates the document by default: an element missing a required
# attribute raises InscoperNBOValidationException, and attributes that carry a
# schema default are written explicitly. Pass False to write exactly what was
# set, at the cost of producing a document that may not be schema-valid.
bin_data = inscoper_nbo.BinData()
bin_data.setBigEndian(True)
length = inscoper_nbo.NonNegativeLong_Type()
length.set(12)
bin_data.setLength(length)
print(bin_data.toXmlString()) # validated: Compression="none" is written
print(bin_data.toXmlString(False)) # as set: Compression is omitted
#include <NBO/NBO/BinData.h>
#include <NBO/NBO/Denomination_Type.h>
#include <NBO/NBO/Image.h>
#include <NBO/NBO/ImageID_Type.h>
#include <NBO/NBO/NonNegativeLong_Type.h>
#include <NBO/NBO/StageLabel.h>
#include <filesystem>
#include <iostream>
#include <memory>
using namespace Inscoper;
int main() {
// Build a small tree: an image carrying three stage positions
NBO::Image image;
NBO::ImageID_TypePtr imageId = std::make_shared<NBO::ImageID_Type>();
imageId->set("Image:1");
image.setID(imageId);
NBO::Denomination_TypePtr name = std::make_shared<NBO::Denomination_Type>();
name->set("Field 1");
image.setName(name);
const float positions[3][2] = {{0.0f, 0.0f}, {120.5f, 0.0f}, {241.0f, 0.0f}};
for (int index = 0; index < 3; ++index) {
NBO::StageLabelPtr stageLabel = std::make_shared<NBO::StageLabel>();
stageLabel->setName("Position " + std::to_string(index));
stageLabel->setX(positions[index][0]);
stageLabel->setY(positions[index][1]);
image.addToStageLabel_List(stageLabel);
}
// Step 1: Serialize to a string
std::cout << image.toXmlString() << std::endl;
// Step 2: Serialize to a file
std::filesystem::path outputPath = std::filesystem::temp_directory_path() / "image.xml";
image.toXmlFile(outputPath.string());
std::cout << "Written to " << outputPath.string() << std::endl;
// Step 3: Control validation on export
// Export validates the document by default: an element missing a required
// attribute throws InscoperNBOValidationException, and attributes that carry a
// schema default are written explicitly. Pass false to write exactly what was
// set, at the cost of producing a document that may not be schema-valid.
NBO::BinData binData;
binData.setBigEndian(true);
NBO::NonNegativeLong_TypePtr length = std::make_shared<NBO::NonNegativeLong_Type>();
length->set(12);
binData.setLength(length);
std::cout << binData.toXmlString() << std::endl; // validated: Compression="none"
std::cout << binData.toXmlString(false) << std::endl; // as set: Compression is omitted
return 0;
}
import com.inscoper.nbo.BinData;
import com.inscoper.nbo.Denomination_Type;
import com.inscoper.nbo.Image;
import com.inscoper.nbo.ImageID_Type;
import com.inscoper.nbo.NonNegativeLong_Type;
import com.inscoper.nbo.StageLabel;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ExportXml {
public static void main(String[] args) {
// Build a small tree: an image carrying three stage positions
Image image = new Image();
ImageID_Type imageId = new ImageID_Type();
imageId.set("Image:1");
image.setID(imageId);
Denomination_Type name = new Denomination_Type();
name.set("Field 1");
image.setName(name);
float[][] positions = {{0.0f, 0.0f}, {120.5f, 0.0f}, {241.0f, 0.0f}};
for (int index = 0; index < positions.length; index++) {
StageLabel stageLabel = new StageLabel();
stageLabel.setName("Position " + index);
stageLabel.setX(positions[index][0]);
stageLabel.setY(positions[index][1]);
image.addToStageLabel_List(stageLabel);
}
// Step 1: Serialize to a string
System.out.println(image.toXmlString());
// Step 2: Serialize to a file
Path outputPath = Paths.get(System.getProperty("java.io.tmpdir"), "image.xml");
image.toXmlFile(outputPath.toString());
System.out.println("Written to " + outputPath);
// Step 3: Control validation on export
// Export validates the document by default: an element missing a required
// attribute throws InscoperNBOValidationException, and attributes that carry a
// schema default are written explicitly. Pass false to write exactly what was
// set, at the cost of producing a document that may not be schema-valid.
BinData binData = new BinData();
binData.setBigEndian(true);
NonNegativeLong_Type length = new NonNegativeLong_Type();
length.set(12);
binData.setLength(length);
System.out.println(binData.toXmlString()); // validated: Compression="none"
System.out.println(binData.toXmlString(false)); // as set: Compression is omitted
}
}
Import from XML¶
Imported documents are checked element by element, so a malformed identifier is reported at import instead of surfacing later in the pipeline.
import inscoper_nbo
SAMPLE_PATH = "instrument_sample.xml"
# Step 1: Import from a string
# Importing replaces the whole content of the target object.
image = inscoper_nbo.Image()
image.fromXmlString(
"""<?xml version="1.0"?>
<Image ID="Image:1" Name="Field 1">
<StageLabel Name="Position 0" X="0" Y="0" />
<StageLabel Name="Position 1" X="120.5" Y="0" />
</Image>"""
)
print(image.getID().get(), image.getName().get())
print(len(image.getStageLabel_List()))
# Step 2: Import from a file
instrument = inscoper_nbo.Instrument()
instrument.fromXmlFile(SAMPLE_PATH)
print(instrument.getID().get())
for objective in instrument.getObjective_List():
print(objective.getModel(), objective.getMagnification())
# Step 3: Imported documents are validated
# Values that violate a schema restriction raise InscoperNBOValidationException,
# which keeps invalid metadata out of the model.
non_compliant = """<?xml version="1.0"?>
<Image ID="NotAnImageIdentifier" />"""
try:
image.fromXmlString(non_compliant)
except inscoper_nbo.InscoperNBOValidationException as error:
print(f"Rejected document: {error}")
# Pass False to import a non-compliant document as it is
image.fromXmlString(non_compliant, False)
print(image.getID().get())
#include <NBO/NBO/Image.h>
#include <NBO/NBO/Instrument.h>
#include <NBO/Shared/Exception/InscoperNBOException.h>
#include <iostream>
using namespace Inscoper;
const std::string SAMPLE_PATH = "instrument_sample.xml";
int main() {
// Step 1: Import from a string
// Importing replaces the whole content of the target object.
NBO::Image image;
image.fromXmlString(R"(<?xml version="1.0"?>
<Image ID="Image:1" Name="Field 1">
<StageLabel Name="Position 0" X="0" Y="0" />
<StageLabel Name="Position 1" X="120.5" Y="0" />
</Image>)");
std::cout << image.getID()->get() << " " << image.getName()->get() << std::endl;
std::cout << image.getStageLabel_List().size() << std::endl;
// Step 2: Import from a file
NBO::Instrument instrument;
instrument.fromXmlFile(SAMPLE_PATH);
std::cout << instrument.getID()->get() << std::endl;
for (const auto &objective : instrument.getObjective_List()) {
std::cout << objective->getModel() << " " << objective->getMagnification() << std::endl;
}
// Step 3: Imported documents are validated
// Values that violate the schema restrictions throw
// InscoperNBOValidationException, which keeps invalid metadata out of the model.
const std::string nonCompliant = R"(<?xml version="1.0"?>
<Image ID="NotAnImageIdentifier" />)";
try {
image.fromXmlString(nonCompliant);
} catch (const NBO::InscoperNBOValidationException &error) {
std::cout << "Rejected document: " << error.what() << std::endl;
}
// Pass false to import a non-compliant document as it is
image.fromXmlString(nonCompliant, false);
std::cout << image.getID()->get() << std::endl;
return 0;
}
import com.inscoper.nbo.Image;
import com.inscoper.nbo.Instrument;
import com.inscoper.nbo.Objective;
public class ImportXml {
static final String SAMPLE_PATH = "instrument_sample.xml";
public static void main(String[] args) {
// Step 1: Import from a string
// Importing replaces the whole content of the target object.
Image image = new Image();
image.fromXmlString("""
<?xml version="1.0"?>
<Image ID="Image:1" Name="Field 1">
<StageLabel Name="Position 0" X="0" Y="0" />
<StageLabel Name="Position 1" X="120.5" Y="0" />
</Image>""");
System.out.println(image.getID().get() + " " + image.getName().get());
System.out.println(image.getStageLabel_List().size());
// Step 2: Import from a file
Instrument instrument = new Instrument();
instrument.fromXmlFile(SAMPLE_PATH);
System.out.println(instrument.getID().get());
for (Objective objective : instrument.getObjective_List()) {
System.out.println(objective.getModel() + " " + objective.getMagnification());
}
// Step 3: Imported documents are validated
// Values that violate the schema restrictions throw
// InscoperNBOValidationException, which keeps invalid metadata out of the model.
String nonCompliant = """
<?xml version="1.0"?>
<Image ID="NotAnImageIdentifier" />""";
try {
image.fromXmlString(nonCompliant);
} catch (Exception error) {
System.out.println("Rejected document: " + error.getMessage());
}
// Pass false to import a non-compliant document as it is
image.fromXmlString(nonCompliant, false);
System.out.println(image.getID().get());
}
}