public void Expand(Profile.ProfileStructureComponent structure) { if (structure.Differential == null) throw Error.Argument("structure", "structure does not contain a differential specification"); var differential = structure.Differential; var baseStructure = _loader.LocateBaseStructure(structure.TypeElement); if (baseStructure == null) throw Error.InvalidOperation("Could not locate the base profile for type {0}", structure.TypeElement.ToString()); if(baseStructure.Snapshot == null) throw Error.InvalidOperation("Base definition to use for expansion lacks a snapshot representation"); // var baseUri = StructureLoader.BuildBaseStructureUri(structure.TypeElement).ToString(); var snapshot = (Profile.ConstraintComponent)baseStructure.Snapshot.DeepCopy(); //DSTU1 //snapshot.SetStructureForm(StructureForm.Snapshot); //snapshot.SetStructureBaseUri(baseUri.ToString()); //mergeStructure(snapshot, differential); var fullDifferential = new DifferentialTreeConstructor(differential).MakeTree(); var snapNav = new ElementNavigator(snapshot); snapNav.MoveToFirstChild(); var diffNav = new ElementNavigator(fullDifferential); diffNav.MoveToFirstChild(); merge(snapNav, diffNav); //TODO: Merge search params? snapNav.CommitChanges(); structure.Snapshot = snapNav.Elements; }
/// <summary> /// Insert the children of the source navigator under the node pointed to by this Navigator. /// </summary> /// <param name="dest"></param> /// <param name="source"></param> /// <returns></returns> public static bool CopyChildren(this BaseElementNavigator dest, ElementNavigator source) { if (dest.HasChildren) return false; // Protect children from being overwritten if (!source.MoveToFirstChild()) return true; // Nothing to copy, but successful anyway bool firstChild = true; do { var copiedChild = (ElementDefinition)source.Current.DeepCopy(); if (firstChild) { // The first time, create a new child in the destination dest.InsertFirstChild(copiedChild); firstChild = false; } else // Then insert other childs after that dest.InsertAfter(copiedChild); // If there are nested children in the source, insert them under // the newly inserted node in the destination if (source.HasChildren) dest.CopyChildren(source); } while (source.MoveToNext()); // Bring both source & destination back one step to the original parents source.MoveToParent(); dest.MoveToParent(); return true; }
public void Generate(StructureDefinition structure) { if (structure.Differential == null) throw Error.Argument("structure", "structure does not contain a differential specification"); if (structure.ConstrainedType != null) throw Error.Argument("structure", "structure is not a constraint or extension"); if(structure.Base == null) throw Error.Argument("structure", "structure is a constraint, but no base has been specified"); var differential = structure.Differential; var baseStructure = _resolver.GetStructureDefinition(structure.Base); if (baseStructure == null) throw Error.InvalidOperation("Could not locate the base StructureDefinition for url " + structure.Base); if (baseStructure.Snapshot == null) throw Error.InvalidOperation("Snapshot generator required the base at {0} to have a snapshot representation", structure.Base); var snapshot = (StructureDefinition.StructureDefinitionSnapshotComponent)baseStructure.Snapshot.DeepCopy(); var snapNav = new ElementNavigator(snapshot.Element); snapNav.MoveToFirstChild(); // Fill out the gaps (mostly missing parents) in the differential representation var fullDifferential = new DifferentialTreeConstructor(differential.Element).MakeTree(); var diffNav = new ElementNavigator(fullDifferential); diffNav.MoveToFirstChild(); merge(snapNav, diffNav); structure.Snapshot = new StructureDefinition.StructureDefinitionSnapshotComponent() { Element = snapNav.ToListOfElements() }; }
/// <summary> /// Rewrites the Path's of the elements in a structure so they are based on the given path: the root /// of the given structure will become the given path, it's children will be relocated below that path /// </summary> /// <param name="root">The structure that will be rebased on the path</param> /// <param name="path">The path to rebase the structure on</param> public static void Rebase(this StructureDefinition root, string path) { var nav = new ElementNavigator(root); if (nav.MoveToFirstChild()) { var newPaths = new List <string>() { path }; rebaseChildren(nav, path, newPaths); var snapshot = root.Snapshot.Element; // Can only change the paths after navigating the tree, otherwise the // navigation functions (which are based on the paths) won't function correctly for (var i = 0; i < root.Snapshot.Element.Count; i++) { root.Snapshot.Element[i].Path = newPaths[i]; } root.Differential = null; // this is now invalid, because the snapshot has changed } }
public static bool ExpandElement(this ElementNavigator nav, ArtifactResolver source) { if (source == null) { throw Error.ArgumentNull("source"); } if (nav.Current == null) { throw Error.ArgumentNull("Navigator is not positioned on an element"); } if (nav.HasChildren) { return(true); // already has children, we're not doing anything extra } var defn = nav.Current; if (!String.IsNullOrEmpty(defn.NameReference)) { var sourceNav = new ElementNavigator(nav); var success = sourceNav.JumpToNameReference(defn.NameReference); if (!success) { throw Error.InvalidOperation("Trying to navigate down a node that has a nameReference of '{0}', which cannot be found in the StructureDefinition".FormatWith(defn.NameReference)); } nav.CopyChildren(sourceNav); } else if (defn.Type != null && defn.Type.Count > 0) { if (defn.Type.Count > 1) { throw new NotSupportedException("Element at path {0} has a choice of types, cannot expand".FormatWith(nav.Path)); } else { var coreType = source.GetStructureDefinitionForCoreType(defn.Type[0].Code); if (coreType == null) { throw Error.NotSupported("Trying to navigate down a node that has a declared base type of '{0}', which is unknown".FormatWith(defn.Type[0].Code)); } if (coreType.Snapshot == null) { throw Error.NotSupported("Found definition of base type '{0}', but is does not contain a snapshot representation".FormatWith(defn.Type[0].Code)); } var sourceNav = new ElementNavigator(coreType.Snapshot.Element); sourceNav.MoveToFirstChild(); nav.CopyChildren(sourceNav); } } return(true); }
public XElement generateStructureTable(Profile.ProfileStructureComponent structure, bool diff, Profile profile) { HierarchicalTableGenerator gen = new HierarchicalTableGenerator(_pkp); var model = TableModel.CreateNormalTable(); // List<Profile.ElementComponent> list = diff ? structure.getDifferential().getElement() : structure.getSnapshot().getElement(); DSTU2 var list = structure.Element; var nav = new ElementNavigator(structure); nav.MoveToFirstChild(); genElement(gen, model.Rows, nav, profile, true); return gen.generate(model); }
public XElement generateStructureTable(String defFile, Profile.ProfileStructureComponent structure, bool diff, String imageFolder, bool inlineGraphics, Profile profile, string profileUrl, String profileBaseFileName) { HierarchicalTableGenerator gen = new HierarchicalTableGenerator(imageFolder, inlineGraphics); TableModel model = gen.initNormalTable(); // List<Profile.ElementComponent> list = diff ? structure.getDifferential().getElement() : structure.getSnapshot().getElement(); DSTU2 var list = structure.Element; var nav = new ElementNavigator(structure); nav.MoveToFirstChild(); genElement(defFile == null ? null : defFile+"#"+structure.Name+".", gen, model.getRows(), nav, profile, diff, profileUrl, profileBaseFileName); return gen.generate(model); }
private void merge(ElementNavigator snap, ElementNavigator diff) { (new ElementDefnMerger(_markChanges)).Merge(snap.Current, diff.Current); // If there are children, move into them, and recursively merge them if (diff.MoveToFirstChild()) { if (!snap.HasChildren) { // The differential moves into an element that has no children in the base. // This is allowable if the base's element has a nameReference or a TypeRef, // in which case needs to be expanded before we can move to the path indicated // by the differential if (snap.Current.Type.Count > 1) throw new NotSupportedException("Differential has a constraint on a choice element {0}, but does so without using a type slice".FormatWith(diff.Path)); expandBaseElement(snap, diff); } // Due to how MoveToFirstChild() works, we have to move to the first matching *child* // when entering the loop for the first time, after that we can look for the next // matching *sibling*. bool firstEntry = true; do { if ((firstEntry && !snap.MoveToChild(diff.PathName)) || (!firstEntry && !snap.MoveTo(diff.PathName)) ) // HACK: I don't think it should be allowed for a diff to list constraints in the wrong order... { throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base", diff.Path); } firstEntry = false; // Child found in both, merge them if (countChildNameRepeats(diff) > 1 || diff.Current.IsExtension()) { // The child in the diff repeats or we recognize it as an extension slice -> we're on the first element of a slice! mergeSlice(snap, diff); } else merge(snap, diff); } while (diff.MoveToNext()); // After the merge, return the diff and snapho back to their original position diff.MoveToParent(); snap.MoveToParent(); } }
/// <summary> /// Will match up the children of the current element in diffNav to the children of the element in snapNav. /// </summary> /// <param name="snapNav"></param> /// <param name="diffNav"></param> /// <returns>Returns a list of Bookmark combinations, the first bookmark pointing to an element in the base, /// the second a bookmark in the diff that matches the bookmark in the base.</returns> /// <remarks>Will match slices to base elements, re-sliced slices to slices and type-slice shorthands to choie elements. /// Note that this function may expand snapNav when it encounters paths in the differential that move into the complex types /// of one of snap's elements. (NO NEED, it just has to match direct children, not deeper) /// This function assumes the differential is not sparse: it must have parent nodes for all child constraint paths. /// </remarks> public List<MatchInfo> Match(ElementNavigator snapNav, ElementNavigator diffNav) { if (!snapNav.HasChildren) throw Error.Argument("snapNav", "Cannot match base to diff: element '{0}' in snap has no children".FormatWith(snapNav.PathName)); if (!diffNav.HasChildren) throw Error.Argument("diffNav", "Cannot match base to diff: element '{0}' in diff has no children".FormatWith(diffNav.PathName)); // These bookmarks are used only in the finally {} to make sure we don't alter the position of the navs when leaving the merger var baseStartBM = snapNav.Bookmark(); var diffStartBM = diffNav.Bookmark(); snapNav.MoveToFirstChild(); diffNav.MoveToFirstChild(); var choiceNames = listChoiceElements(snapNav); var result = new List<MatchInfo>(); try { do { // First, match directly -> try to find the child in base with the same name as the path in the diff if (snapNav.PathName != diffNav.PathName && !snapNav.MoveToNext(diffNav.PathName)) { // Not found, maybe this is a type slice shorthand, look if we have a matching choice prefix in snap var typeSliceShorthand = diffNav.PathName; // Try to match nameXXXXX to name[x] var matchingChoice = choiceNames.SingleOrDefault(prefix => isPossibleTypeSlice(prefix, typeSliceShorthand)); if (matchingChoice != null) snapNav.MoveToNext(matchingChoice); else throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base".FormatWith(diffNav.Path)); } result.AddRange(constructMatch(snapNav, diffNav)); } while (diffNav.MoveToNext()); } finally { snapNav.ReturnToBookmark(baseStartBM); diffNav.ReturnToBookmark(diffStartBM); } return result; }
/// <summary> /// Rewrites the Path's of the elements in a structure so they are based on the given path: the root /// of the given structure will become the given path, it's children will be relocated below that path /// </summary> /// <param name="root">The structure that will be rebased on the path</param> /// <param name="path">The path to rebase the structure on</param> public static void Rebase(this IElementList root, string path) { var nav = new ElementNavigator(root.Element); if (nav.MoveToFirstChild()) { var newPaths = new List<string>() { path }; rebaseChildren(nav, path, newPaths); var snapshot = root.Element; // Can only change the paths after navigating the tree, otherwise the // navigation functions (which are based on the paths) won't function correctly for (var i = 0; i < root.Element.Count; i++) root.Element[i].Path = newPaths[i]; } }
//private static void mergeStructure(Profile.ConstraintComponent snapshot, Profile.ConstraintComponent differential) //{ // if (differential.Name != null) snapshot.Name = differential.Name; // if (differential.Publish != null) snapshot.Publish = differential.Publish; // if (differential.Purpose != null) snapshot.Purpose = differential.Purpose; //} private void merge(ElementNavigator snap, ElementNavigator diff) { mergeElementAttributes(snap.Current, diff.Current); // If there are children, move into them, and recursively merge them if (diff.MoveToFirstChild()) { if (!snap.HasChildren) { // The differential moves into an element that has no children in the base. // This is allowable if the base's element has a nameReference or a TypeRef, // in which case needs to be expanded before we can move to the path indicated // by the differential expandBaseElement(snap, diff); } // Due to how MoveToFirstChild() works, we have to move to the first matching *child* // when entering the loop for the first time, after that we can look for the next // matching *sibling*. bool firstEntry = true; do { if( (firstEntry && !snap.MoveToChild(diff.PathName)) || (!firstEntry && !snap.MoveToNext(diff.PathName)) ) throw Error.InvalidOperation("Differential has a constraint for path '{0}', which does not exist in its base", diff.PathName); firstEntry = false; // Child found in both, merge them if (countChildNameRepeats(diff) > 1 || diff.Current.IsExtension()) { // The child in the diff repeats or we recognize it as an extension slice -> we're on the first element of a slice! mergeSlice(snap, diff); } else merge(snap, diff); } while (diff.MoveToNext()); // After the merge, return the diff and snapho back to their original position diff.MoveToParent(); snap.MoveToParent(); } }
/// <summary> /// Insert the children of the current source node under the node pointed to by the destination. /// </summary> /// <param name="dest"></param> /// <param name="source"></param> /// <returns></returns> public static bool CopyChildren(this BaseElementNavigator dest, ElementNavigator source) { if (dest.HasChildren) { return(false); // Protect children from being overwritten } if (!source.MoveToFirstChild()) { return(true); // Nothing to copy, but successful anyway } bool firstChild = true; do { var copiedChild = (ElementDefinition)source.Current.DeepCopy(); if (firstChild) { // The first time, create a new child in the destination dest.InsertFirstChild(copiedChild); firstChild = false; } else { // Then insert other childs after that dest.InsertAfter(copiedChild); } // If there are nested children in the source, insert them under // the newly inserted node in the destination if (source.HasChildren) { dest.CopyChildren(source); } }while (source.MoveToNext()); // Bring both source & destination back one step to the original parents source.MoveToParent(); dest.MoveToParent(); return(true); }
/// <summary> /// Rewrites the Path's of the elements in a structure so they are based on the given path: the root /// of the given structure will become the given path, it's children will be relocated below that path /// </summary> /// <param name="root">The structure that will be rebased on the path</param> /// <param name="path">The path to rebase the structure on</param> public static void Rebase(this StructureDefinition root, string path) { var nav = new ElementNavigator(root); if (nav.MoveToFirstChild()) { var newPaths = new List<string>() { path }; rebaseChildren(nav, path, newPaths); var snapshot = root.Snapshot.Element; // Can only change the paths after navigating the tree, otherwise the // navigation functions (which are based on the paths) won't function correctly for (var i = 0; i < root.Snapshot.Element.Count; i++) root.Snapshot.Element[i].Path = newPaths[i]; root.Differential = null; // this is now invalid, because the snapshot has changed } }
/// <summary> /// Rewrites the Path's of the elements in a structure so they are based on the given path: the root /// of the given structure will become the given path, it's children will be relocated below that path /// </summary> /// <param name="root">The structure that will be rebased on the path</param> /// <param name="path">The path to rebase the structure on</param> public static void Rebase(this IElementList root, string path) { var nav = new ElementNavigator(root.Element); if (nav.MoveToFirstChild()) { var newPaths = new List <string>() { path }; rebaseChildren(nav, path, newPaths); var snapshot = root.Element; // Can only change the paths after navigating the tree, otherwise the // navigation functions (which are based on the paths) won't function correctly for (var i = 0; i < root.Element.Count; i++) { root.Element[i].Path = newPaths[i]; } } }
public static bool ExpandElement(this ElementNavigator nav, ArtifactResolver source) { if (source == null) throw Error.ArgumentNull("source"); if (nav.Current == null) throw Error.ArgumentNull("Navigator is not positioned on an element"); if (nav.HasChildren) return true; // already has children, we're not doing anything extra var defn = nav.Current; if (!String.IsNullOrEmpty(defn.NameReference)) { var sourceNav = new ElementNavigator(nav); var success = sourceNav.JumpToNameReference(defn.NameReference); if(!success) throw Error.InvalidOperation("Trying to navigate down a node that has a nameReference of '{0}', which cannot be found in the StructureDefinition".FormatWith(defn.NameReference)); nav.CopyChildren(sourceNav); } else if (defn.Type != null && defn.Type.Count > 0) { if (defn.Type.Count > 1) throw new NotSupportedException("Element at path {0} has a choice of types, cannot expand".FormatWith(nav.Path)); else { var coreType = source.GetStructureDefinitionForCoreType(defn.Type[0].Code); if (coreType == null) throw Error.NotSupported("Trying to navigate down a node that has a declared base type of '{0}', which is unknown".FormatWith(defn.Type[0].Code)); if (coreType.Snapshot == null) throw Error.NotSupported("Found definition of base type '{0}', but is does not contain a snapshot representation".FormatWith(defn.Type[0].Code)); var sourceNav = new ElementNavigator(coreType.Snapshot.Element); sourceNav.MoveToFirstChild(); nav.CopyChildren(sourceNav); } } return true; }
private void genElement(HierarchicalTableGenerator gen, List<Row> rows, ElementNavigator nav, Profile profile, bool showMissing) { var element = nav.Current; if(onlyInformationIsMapping(nav.Structure.Element, element)) return; // we don't even show it in this case Row row = new Row(); row.setAnchor(element.Path); String s = element.GetNameFromPath(); bool hasDef = element.Definition != null; bool ext = false; if (s == "extension" || s == "modifierExtension") { row.setIcon("icon_extension_simple.png"); ext = true; } else if (!hasDef || element.Definition.Type == null || element.Definition.Type.Count == 0) { row.setIcon("icon_element.gif"); } else if (hasDef && element.Definition.Type.Count > 1) { if (allTypesAre(element.Definition.Type, "ResourceReference")) row.setIcon("icon_reference.png"); else row.setIcon("icon_choice.gif"); } else if (hasDef && element.Definition.Type[0].Code.StartsWith("@")) { //TODO: That's not a legal code, will this ever appear? //I am pretty sure this depends on ElementDefn.NameReference row.setIcon("icon_reuse.png"); } else if (hasDef && _pkp.isPrimitive(element.Definition.Type[0].Code)) row.setIcon("icon_primitive.png"); else if (hasDef && _pkp.isReference(element.Definition.Type[0].Code)) row.setIcon("icon_reference.png"); else if (hasDef && _pkp.isDataType(element.Definition.Type[0].Code)) row.setIcon("icon_datatype.gif"); else row.setIcon("icon_resource.png"); var reference = _pkp.GetLinkForElementDefinition(nav.Structure, profile, element); //String reference = defPath == null ? null : defPath + makePathLink(element); UnusedTracker used = new UnusedTracker(); used.used = true; Cell left = new Cell(null, reference, s, !hasDef ? null : element.Definition.Formal, null); row.getCells().Add(left); if (ext) { // If this element (row) in the table is an extension... if (element.Definition != null && element.Definition.Type.Count == 1 && element.Definition.Type[0].Profile != null) { Profile.ProfileExtensionDefnComponent extDefn = _pkp.getExtensionDefinition(profile, element.Definition.Type[0].Profile); if (extDefn == null) { row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null)); row.getCells().Add(new Cell(null, null, "?? "+element.Definition.Type[0].Profile, null, null)); generateDescription(gen, row, element, null, used.used, element.Definition.Type[0].Profile, profile); } else { row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, extDefn.Definition, used), null, null)); genTypes(gen, row, extDefn.Definition, profile); generateDescription(gen, row, element, extDefn.Definition, used.used, element.Definition.Type[0].Profile, profile); } } else if (element.Definition != null) { row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null)); genTypes(gen, row, element.Definition, profile); generateDescription(gen, row, element, null, used.used, null, profile); } else { row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null)); row.getCells().Add(new Cell()); generateDescription(gen, row, element, null, used.used, null, profile); } } else { row.getCells().Add(new Cell(null, null, !hasDef ? null : describeCardinality(element.Definition, null, used), null, null)); if (element.Definition != null) genTypes(gen, row, element.Definition, profile); else row.getCells().Add(new Cell()); generateDescription(gen, row, element, null, used.used, null, profile); } if (element.Slicing != null) { row.setIcon("icon_slice.png"); row.getCells()[2].getPieces().Clear(); foreach (Cell cell in row.getCells()) foreach (Piece p in cell.getPieces()) { p.addStyle("font-style: italic"); } } if (used.used || showMissing) rows.Add(row); if (!used.used) { foreach (Cell cell in row.getCells()) foreach (Piece p in cell.getPieces()) { p.setStyle("text-decoration:line-through"); p.setReference(null); } } else { if (nav.MoveToFirstChild()) { do { genElement(gen, row.getSubRows(), nav, profile, showMissing); } while (nav.MoveToNext()); nav.MoveToParent(); } } }