ElementModel, manipulating IResource and ISourceNode
As stated in IResource, IResource
is immutable, and so is ISourceNode
that it is based on.
Still, there are cases where you would want to manipulate a resource, e.g. add, change or remove elements. The namespace Vonk.Core.ElementModel
has methods to do so. All of these methods do NOT change the original structure (the input IResource or ISourceNode), but instead return an updated structure.
ISourceNode manipulation
All the ISourceNode
extension methods can be used on IResource
as well. If you need an IResource
as result, just turn the resulting ISourceNode
to an IResource
again. So if you added an element to an ISourceNode:
IResource result = input.AddIfNotExists(SourceNode.Valued("active", "false")).ToIResource(input.InformationModel);
For some of the more common extension methods we provide an overload on IResource that does this for you, like IResource.Patch(...)
All the methods below are in the namespace Vonk.Core.ElementModel.ISourceNodeExtensions
:
- Add(this ISourceNode original, ISourceNode newChild) ISourceNode
Add the
newChild
as a child node to theoriginal
. It will be added at the end of the Children.
- Add(this ISourceNode original, ITypedElement newChild) ISourceNode
Overload of Add(ISourceNode newChild) that lets you add an ITypedElement as new child.
- AddIf(this ISourceNode original, ISourceNode newChild, Func<ISourceNode, bool> addIf) ISourceNode
Add the
newChild
as a child node to theoriginal
if theaddIf
predicate onoriginal
is met. It will be added at the end of the Children.
- Add(this ISourceNode original, TypedElement newChild, Func<ISourceNode, bool> addIf) ISourceNode
Similar to AddIf(ISourceNode newChild, Func<ISourceNode, bool> addIf) that lets you add an ITypedElement as new child.
- AddIfNotExists(this ISourceNode original, ISourceNode newChild) ISourceNode
Add the
newChild
as a child node to theoriginal
if there is no child with the same name yet. It will be added at the end of the Children.
- AddIfNotExists(this ISourceNode original, ISourceNode newChild, Func<ISourceNode, bool> exists) ISourceNode
Add the
newChild
as a child node to theoriginal
if theexists
predicate onoriginal
is not satisfied. This is likeAddIfNotExist(ISourceNode newChild)
, but here you get to specify what ‘exists’ means. It will be added at the end of the Children.
- AddIfNotExists(this ISourceNode original, string location, ISourceNode newChild) ISourceNode
Navigate to
location
. Then add thenewChild
as a child node to theoriginal
if there is no child with the same name yet.
- AddIfNotExists(this ISourceNode original, ISourceNode newChild, string location, Func<ISourceNode, bool> exists) ISourceNode
Navigate to
location
. Then add thenewChild
as a child node if theexists
predicate on the current node is not satisfied.
- AnnotateWith<T>(this ISourceNode original, T annotation, bool hideExisting = false) -> ISourceNode
Add an annotation of type T to the
original
. When hideExisting == true, any existing annotations of type T are not visible anymore on the returned ISourceNode.
- GetBoundAnnotation<T>(this ISourceNode original, ) where T : class, IBoundAnnotation -> T
Retrieve an annotation that is bound directly to
original
, not to any of the nodes it may decorate. (ISourceNode is immutable, to changes are usually a pile of wrappers around theoriginal
SourceNode, and each of the wrappers can add / replace annotations.)
- RemoveEmptyNodes(this ISourceNode original, ISourceNode newChild) ISourceNode
Remove any nodes that have no value or children. This happens recursively: if a node has only children with empty values, it will be removed as well. This way the returned ISourceNode conforms to the invariant in the FHIR specification that an element either has a value or children.
- RemoveEmptyNodes(this ISourceNode original, ISourceNode newChild, string location) ISourceNode
Remove any nodes that have no value or children, from the specified
location
downwards. This happens recursively: if a node has only children with empty values, it will be removed as well.
- Child(this ISourceNode original, string name, int arrayIndex = 0) ISourceNode
Convenience method to get the child with name
name
at positionarrayIndex
. Usually used to get a child of which you know there is only one:patientNode.Child("active")
- ChildString(this ISourceNode original, string name, int arrayIndex = 0) ISourceNode
Convenience method to get the value of the child with name
name
at positionarrayIndex
. Usually used to get a child of which you know there is only one:patientNode.ChildString("id")
- ForceAdd(this ISourceNode original, string addAt, ISourceNode newChild) ISourceNode
Add the
newChild
at locationaddAt
. Create the intermediate nodes if necessary .
- AddOrReplace(this ISourceNode original, Func<ISourceNode, bool> match, ISourceNode toAdd, Func<ISourceNode, ISourceNode> replace) ISourceNode
Find any child nodes of
original
that match thematch
predicate. Applyreplace
to them. If none are found, addtoAdd
as new child.
- AddOrReplace(this ISourceNode original, ISourceNode toAdd, Func<ISourceNode, ISourceNode> replace) ISourceNode
Optimized overload of the previous method for matching on the node name. It will perform
replace
on any child node oforiginal
with the same name astoAdd
. If none are found it will addtoAdd
as new child node.
- Remove(this ISourceNode original, string location) ISourceNode
Remove the node at
location
, if any. If that results in parent nodes becoming empty (no Text, no Children), those are removed as well.
- SelectNodes(this ISourceNode original, string fhirPath) IEnumerable<ISourceNode>
Run
fhirPath
over theoriginal
, but with the limitations of untyped nodes. It will return the matching nodes. Use valueDateTime/valueBoolean instead of just ‘value’ for choice types. Only use this method if you are familiar with the differences in the naming of nodes between ISourceNode and ITypedElement.
- SelectText(this ISourceNode original, string fhirPath) string
Run
fhirPath
over theoriginal
, but with the limitations of untyped nodes. Returns theText
of the first matching node. Use valueDateTime/valueBoolean instead of just ‘value’ for choice types. Only use this method if you are familiar with the differences in the naming of nodes between ISourceNode and ITypedElement.
- Patch(this ISourceNode original, string location, Func<ISourceNode, ISourceNode> patch) ISourceNode
Find any nodes at
location
and applypatch
to them. Forpatch
you can use other methods listed here likeRename
,Add
orRevalue
.location
is evaluated as a fhirpath statement, with the limitations of untyped nodes.
- Patch(this ISourceNode original, string[] locations, Func<ISourceNode, ISourceNode> patch) ISourceNode
Find any nodes having one of the
locations
as their Location and applypatch
to them. If you don’t know exact locations, useoriginal.Patch(location, patch)
, see above.
- ForcePatch(this ISourceNode original, string forcePath, Func<ISourceNode, ISourceNode> patch) ISourceNode
Enforce that
forcePath
exists. Then patch the resulting node(s) withpatch
.
- ForcePatchAt(this ISourceNode original, string fromLocation, string forcePath, Func<ISourceNode, ISourceNode> patch) ISourceNode
For each node matching the
fromLocation
: enforce thatfromLocation.forcePath
exists, then patch the resulting node(s) withpatch
. E.g. someBundle.ForcePatchAt(“entry”, “request”, node => node.Add(SourceNode.Valued(“url”, “someUrl”)) will add request.url with value “someUrl” to every entry.
- Relocate(this ISourceNode original, string newLocation) ISourceNode
Set
original.Location
to the newLocation, and update all its descendants’Location
properties recursively.
- Rename(this ISourceNode original, string newName) ISourceNode
Set
original.Name
to thenewName
.
- Revalue(this ISourceNode original, string newValue) ISourceNode
Set
original.Text
tonewValue
.
- Revalue(this ISourceNode original, Dictionary<string, string> replacements) ISourceNode
replacements
is a dictionary of location + newValue. On each matching location underoriginal
, the value will be set to the according newValue fromreplacements
.
- AnnotateWithSourceNode(this ISourceNode original) ISourceNode
Add
original
as annotation to itself. Very specific use case.
ITypedElement manipulation
All the methods below are in the namespace Vonk.Core.ElementModel.ITypedElementExtensions
:
- Add(this ITypedElement original, ITypedElement newChild, Func<ITypedElement, bool> addIf) ISourceNode
Add
newChild
as child tooriginal
ifaddIf
onoriginal
evaluates to true. Convenience overload ofISourceNodeExtensions.Add(ISourceNode, ITypedElement, Func<ISourceNode, bool>)
- Add(this ITypedElement original, ITypedElement newChild) ISourceNode
Add
newChild
as child tooriginal
. Convenience overload ofISourceNodeExtensions.Add(ISourceNode, ITypedElement)
- AddIfNotExists(this ITypedElement original, ITypedElement newChild) ISourceNode
Add
newChild
as child tooriginal
if no child with the same name exists yet. Convenience overload ofISourceNodeExtensions.AddIfNotExists(ISourceNode, ITypedElement)
- AddIf(this ITypedElement original, ISourceNode newChild, Func<ITypedElement, bool> addIf) ISourceNode
Add
newChild
as child tooriginal
ifaddIf
onoriginal
evaluates to true. Convenience overload ofISourceNodeExtensions.AddIf(ISourceNode, ISourceNode, Func<ISourceNode, bool>)
- method:
Add(this ITypedElement original, ISourceNode newChild) Add
newChild
as child tooriginal
.- method:
AddIfNotExists(this ITypedElement original, ISourceNode newChild) Add
newChild
as child tooriginal
if no child with the same name exists yet. Convenience overload ofAddIfNotExists(ITypedElement, ITypedElement)
- Cache(this ITypedElement original) ITypedElement
Prevent recalculation of the Children upon every access.
- Child(this ITypedElement element, string name, int arrayIndex = 0) ITypedElement
Returns n-th child with the specified
name
, if any.
- ChildString(this ITypedElement element, string name, int arrayIndex = 0) string
Returns the value of the n-th child with the specified
name
as string, if any.
- DefinitionSummary(this ITypedElement element, IStructureDefinitionSummaryProvider provider) IStructureDefinitionSummary
Returns the summary for the actual type of the element. Especially useful if the element is of a choicetype.
- AddParent(this ITypedElement element) ITypedElement
Add
Vonk.Core.ElementModel.IParentProvider
annotations toelement
and its descendants.
- GetParent(this ITypedElement element) ITypedElement
Get the parent of this element, through the
Vonk.Core.ElementModel.IParentProvider
annotation (if present).
- AddTreePath(this ITypedElement element) ITypedElement
Add the
Vonk.Core.ElementModel.ITreePathGenerator
annotation. TreePath is the Location without any indexes (no [n] at the end).
- GetTreePath(this ITypedElement element) string
Get the value of the
Vonk.Core.ElementModel.ITreePathGenerator
annotation, if present. TreePath is the Location without any indexes (no [n] at the end).