Repository navigation
Writing ReqIF
Writing is done by ReqIFSerializer, which implements IReqIFSerializer. You build a ReqIF object graph in memory and the serializer writes it as a .reqif file or a .reqifz archive. This page builds a complete, schema-valid document step by step: a small specification for a coffee machine with three requirements, a status enumeration, rich text and a trace link.
If you haven't yet, read ReqIF Concepts first. The order of the steps below follows the split between types and data described there.
void Serialize(IEnumerable<ReqIF> reqifs, string fileUri);
void Serialize(IEnumerable<ReqIF> reqifs, Stream stream, SupportedFileExtensionKind fileExtensionKind);
Task SerializeAsync(IEnumerable<ReqIF> reqifs, string fileUri, CancellationToken token);
Task SerializeAsync(IEnumerable<ReqIF> reqifs, Stream stream, SupportedFileExtensionKind fileExtensionKind, CancellationToken token);The file extension, or the SupportedFileExtensionKind for a stream, picks the output format:
| Extension | Output |
|---|---|
.reqif |
one ReqIF XML document. Pass exactly one ReqIF. |
.reqifz, .zip
|
a zip archive with one .reqif file per ReqIF you pass |
using ReqIFSharp;
var now = DateTime.UtcNow;
// 1. The document root, header and content
var content = new ReqIFContent();
var reqif = new ReqIF
{
Lang = "en",
TheHeader = new ReqIFHeader
{
Identifier = "header-coffee",
Title = "Coffee machine requirements",
Comment = "Generated with ReqIFSharp",
CreationTime = now,
ReqIFToolId = "my-tool",
ReqIFVersion = "1.0",
SourceToolId = "my-tool"
},
CoreContent = content
};
// 2. Datatypes
var stringType = new DatatypeDefinitionString { Identifier = "dt-string", LongName = "String", MaxLength = 255, LastChange = now };
var xhtmlType = new DatatypeDefinitionXHTML { Identifier = "dt-xhtml", LongName = "Formatted text", LastChange = now };
var statusType = new DatatypeDefinitionEnumeration { Identifier = "dt-status", LongName = "Status", LastChange = now };
var draft = new EnumValue { Identifier = "ev-draft", LongName = "Draft", LastChange = now, Properties = new EmbeddedValue { Key = 0, OtherContent = "" } };
var approved = new EnumValue { Identifier = "ev-approved", LongName = "Approved", LastChange = now, Properties = new EmbeddedValue { Key = 1, OtherContent = "" } };
statusType.SpecifiedValues.Add(draft);
statusType.SpecifiedValues.Add(approved);
content.DataTypes.AddRange(new DatatypeDefinition[] { stringType, xhtmlType, statusType });
// 3. Spec types and their attribute definitions
var idAttribute = new AttributeDefinitionString { Identifier = "ad-id", LongName = "ID", Type = stringType, LastChange = now };
var textAttribute = new AttributeDefinitionXHTML { Identifier = "ad-text", LongName = "Text", Type = xhtmlType, LastChange = now };
var statusAttribute = new AttributeDefinitionEnumeration { Identifier = "ad-status", LongName = "Status", Type = statusType, IsMultiValued = false, LastChange = now };
var requirementType = new SpecObjectType { Identifier = "sot-requirement", LongName = "Requirement", LastChange = now };
requirementType.SpecAttributes.AddRange(new AttributeDefinition[] { idAttribute, textAttribute, statusAttribute });
var specificationType = new SpecificationType { Identifier = "st-document", LongName = "Document", LastChange = now };
var refinesType = new SpecRelationType { Identifier = "srt-refines", LongName = "refines", LastChange = now };
content.SpecTypes.AddRange(new SpecType[] { requirementType, specificationType, refinesType });
// 4. Spec objects with their values
SpecObject CreateRequirement(string id, string text, EnumValue status)
{
var requirement = new SpecObject { Identifier = $"so-{id}", LongName = id, Type = requirementType, LastChange = now };
requirement.Values.Add(new AttributeValueString { Definition = idAttribute, TheValue = id });
requirement.Values.Add(new AttributeValueXHTML { Definition = textAttribute, TheValue = $"<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">{text}</xhtml:div>" });
var statusValue = new AttributeValueEnumeration { Definition = statusAttribute };
statusValue.Values.Add(status);
requirement.Values.Add(statusValue);
content.SpecObjects.Add(requirement);
return requirement;
}
var brew = CreateRequirement("REQ-1", "The machine shall brew a cup of coffee in <xhtml:b>under 30 seconds</xhtml:b>.", approved);
var heat = CreateRequirement("REQ-2", "The water shall be heated to 92 °C before brewing starts.", draft);
var tank = CreateRequirement("REQ-3", "The machine shall warn the user when the water tank is empty.", draft);
// 5. A specification: a tree of SpecHierarchy nodes that point to spec objects
var specification = new Specification { Identifier = "spec-coffee", LongName = "Coffee machine", Type = specificationType, LastChange = now };
var brewNode = new SpecHierarchy { Identifier = "sh-1", Object = brew, LastChange = now };
brewNode.Children.Add(new SpecHierarchy { Identifier = "sh-1-1", Object = heat, LastChange = now });
specification.Children.Add(brewNode);
specification.Children.Add(new SpecHierarchy { Identifier = "sh-2", Object = tank, LastChange = now });
content.Specifications.Add(specification);
// 6. A trace link: REQ-2 refines REQ-1
content.SpecRelations.Add(new SpecRelation { Identifier = "rel-1", Type = refinesType, Source = heat, Target = brew, LastChange = now });
// 7. Write it
var serializer = new ReqIFSerializer();
serializer.Serialize(new[] { reqif }, "coffee.reqif");Read it back with validation to check the result:
var problems = new List<string>();
new ReqIFDeserializer().Deserialize("coffee.reqif", true, (sender, e) => problems.Add(e.Message));
Console.WriteLine(problems.Count == 0 ? "Valid ReqIF" : string.Join(Environment.NewLine, problems));The sections below explain each step.
A ReqIF needs a TheHeader and a CoreContent. In the header, Identifier is required, and tools expect CreationTime, ReqIFToolId, ReqIFVersion ("1.0"), SourceToolId and Title to be filled in. Lang sets the xml:lang of the document.
Each attribute needs a datatype, so define those first and add them to content.DataTypes. An enumeration lists its EnumValues in SpecifiedValues. The schema requires each EnumValue to have Properties with a Key, the numeric value of the literal. OtherContent is free text and can be empty.
A spec type is a template: its SpecAttributes are the fields that every element of that type has. Each attribute definition points to its datatype through Type. For enumerations, IsMultiValued says whether more than one literal can be selected.
A SpecObject has a Type and a Values list. Each attribute value points to its attribute definition through Definition. Only add values for the attributes you want to fill in.
Rich text must be valid XHTML in the XHTML namespace, wrapped in a single element, usually a div:
new AttributeValueXHTML
{
Definition = textAttribute,
TheValue = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:p>First paragraph</xhtml:p><xhtml:ul><xhtml:li>a list item</xhtml:li></xhtml:ul></xhtml:div>"
};The other value types work the same way:
new AttributeValueInteger { Definition = priorityAttribute, TheValue = 3 };
new AttributeValueReal { Definition = weightAttribute, TheValue = 1.25 };
new AttributeValueBoolean { Definition = safetyAttribute, TheValue = true };
new AttributeValueDate { Definition = dueAttribute, TheValue = new DateTime(2027, 1, 31) };A Specification is what users see as a document. Build it from SpecHierarchy nodes: each node points to a spec object through Object and can have its own Children, which gives you chapters and sub-requirements. The spec objects must also be in content.SpecObjects. A spec object can appear in more than one specification.
A SpecRelation links a Source spec object to a Target spec object, with a SpecRelationType that names the kind of link. Relations can have attribute values too: give the relation type SpecAttributes and add Values to the relation, as for spec objects.
var serializer = new ReqIFSerializer();
serializer.Serialize(new[] { reqif }, "coffee.reqif"); // XML
serializer.Serialize(new[] { reqif }, "coffee.reqifz"); // zip archive
await using var stream = File.Create("coffee-async.reqifz");
await serializer.SerializeAsync(new[] { reqif }, stream, SupportedFileExtensionKind.Reqifz, cancellationToken);-
Identifiers must be unique across the whole document, because references in the XML point to them. The schema types them as
xsd:ID: they must start with a letter or an underscore and cannot contain spaces or colons. A bare GUID often starts with a digit and is then invalid, so prefix it:"_" + Guid.NewGuid(). -
Set
LastChangeon every element. The schema requires it. -
Everything you reference must be in
CoreContent. A datatype, spec type or spec object that is used but not added to the matching list ofReqIFContentproduces a document that other tools can't read. Validating the output, as shown above, catches this. -
Using ReqIFSharp.Extensions on a document you built? The extension methods find related elements through the
ReqIFContentproperty of spec types and spec elements. The deserializer sets it; when you build a document yourself, set it too, for examplerequirementType.ReqIFContent = content;, or write the document and read it back. - Modifying an existing document works the same way: read it, change the objects, write it. The namespaces and attributes of the original root element are kept, so the result stays close to the original.
copyright @ Starion Group S.A.