Beispiel #1
0
        SliceAccessorTypes SliceAccessorType(ElementDefinitionNode sliceNode)
        {
            const String fcn = nameof(SliceAccessorType);

            String baseType = sliceNode.FhirType.FriendlyName();

            if (sliceNode.IsListType)
            {
                switch (sliceNode.Element.Max.ToMax())
                {
                case 0:
                    this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node '{sliceNode.FullPath()}' has max of 0. Not sure what I am supposed to do!");
                    return(SliceAccessorTypes.Error);

                case 1:
                    return(SliceAccessorTypes.Single);

                default:
                    return(SliceAccessorTypes.Multiple);
                }
            }
            else
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node '{sliceNode.FullPath()}' unknown base type {baseType}");
                return(SliceAccessorTypes.Error);
            }
        }
Beispiel #2
0
        Element GetItem(ElementDefinitionNode sliceNode, String path)
        {
            const String fcn = nameof(GetItem);

            String[] pathParts         = path.Split('.');
            ElementDefinitionNode node = sliceNode;

            for (Int32 i = 0; i < pathParts.Length; i++)
            {
                String pathPart            = pathParts[i];
                ElementDefinitionNode next = null;
                foreach (ElementDefinitionNode n in node.ChildNodes)
                {
                    if (n.Name == pathPart)
                    {
                        next = n;
                        break;
                    }
                }
                if (next == null)
                {
                    this.Gen.ConversionError(this.GetType().Name, fcn, $"Cant find child node '{pathPart}' in '{sliceNode.FullPath()}'");
                    return(null);
                }
                node = next;
            }
            return(node.Element.Fixed);
        }
Beispiel #3
0
        public CSSliceCreator(String className,
                              CSCodeFormatter csCode,
                              CodeBlockNested subClassBlock,
                              CodeBlockNested methodsBlock,
                              ElementDefinitionNode elementNode,
                              Type fhirBaseClassType)
        {
            if (subClassBlock is null)
            {
                throw new ArgumentNullException(nameof(subClassBlock));
            }
            if (methodsBlock is null)
            {
                throw new ArgumentNullException(nameof(methodsBlock));
            }
            if (elementNode is null)
            {
                throw new ArgumentNullException(nameof(elementNode));
            }

            this.csCode = csCode;
            if (elementNode is null)
            {
                throw new ArgumentNullException(nameof(elementNode));
            }

            this.className         = className;
            this.subClassBlock     = subClassBlock.AppendBlock();
            this.methodsBlock      = methodsBlock.AppendBlock();
            this.elementNode       = elementNode;
            this.fhirBaseClassType = fhirBaseClassType;
        }
Beispiel #4
0
 public GenerateItem(SliceGenerator gen,
                     String nameSpace,
                     String className,
                     String profileType,
                     Type fhirType,
                     OutputLanguageType outputLanguage,
                     ElementDefinitionNode profileElements)
 {
     this.gen             = gen;
     this.nameSpace       = nameSpace;
     this.className       = className;
     this.fhirType        = fhirType;
     this.outputLanguage  = outputLanguage;
     this.profileElements = profileElements;
     this.profileType     = profileType;
 }
Beispiel #5
0
        bool CreateSlice(ElementDefinitionNode elementNode)
        {
            const String fcn = nameof(ProcessResourceConstraint);

            this.gen.ConversionInfo(this.GetType().Name, fcn, $"Processing slice on node {elementNode.Element.Path}");

            List <ElementDefinition.DiscriminatorComponent> d = elementNode.Element.Slicing?.Discriminator;

            if ((d == null) || (d.Count == 0))
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice of element {elementNode.Element.Path} failed. Element lacks slice discriminator");
                return(false);
            }

            return(this.Code.CreateSlice(elementNode));
        }
Beispiel #6
0
        void ProcessProfile(StructureDefinition profile)
        {
            String fcn = nameof(ProcessProfile);

            try
            {
                if (profile.Snapshot == null)
                {
                    SnapshotCreator.Create(profile);
                }
                ElementDefinitionNode profileItems = ElementDefinitionNode.Create(profile);

                String baseFhirResourceName = profile.Type;
                Type   fhirType             = ModelInfo.GetTypeForFhirType(baseFhirResourceName);
                if (fhirType == null)
                {
                    throw new Exception($"Can not find Fhir Resource Class for '{baseFhirResourceName}'");
                }

                String name = $"{profile.Name}Extensions";

                GenerateItem gi = new GenerateItem(this,
                                                   this.NameSpace,
                                                   name,
                                                   profile.Type,
                                                   fhirType,
                                                   this.OutputLanguage,
                                                   profileItems);

                gi.Process();

                if (this.SaveFlag == true)
                {
                    String outputFile = Path.Combine(this.OutputDir, $"{name}.cs");
                    File.WriteAllText(outputFile, gi.GetCode());
                }
            }
            catch (Exception err)
            {
                this.ConversionError(this.GetType().Name, fcn, $"Profile {profile.Name} failed with exception {err.Message}");
            }
        }
Beispiel #7
0
        void CreateSliceAccessor(ElementDefinitionNode sliceNode, String sliceClassName, String sliceInterfaceName)
        {
            String sliceName    = sliceNode.Element.SliceName.ToMachineName();
            String propertyPath = sliceNode.PropertyName;

            String sliceBaseClassName;

            switch (SliceAccessorType(sliceNode))
            {
            case SliceAccessorTypes.Error:
                sliceBaseClassName = $"??";
                break;

            case SliceAccessorTypes.Single:
                sliceBaseClassName = $"ISliceAccessorSingle<{accessorType}>";
                break;

            case SliceAccessorTypes.Multiple:
                sliceBaseClassName = $"ISliceAccessorMultiple<{accessorType}>";
                break;

            default:
                throw new NotImplementedException("Unknown SliceAccessorTypes value");
            }

            this.methodsBlock
            .BlankLine()
            .SummaryOpen()
            .Summary($"Extension method to return slice {sliceName} on {elementNode.Name}")
            .SummaryClose()
            .Example(
                $"{this.fhirBaseClassType.FriendlyName()} resource = new {this.fhirBaseClassType.FriendlyName()}();",
                $"{this.className}.{sliceInterfaceName} sliceAccessor = resource.{propertyPath}.{sliceName}();"
                )
            .AppendCode($"public static {sliceInterfaceName} {sliceName}(this {baseTypeName} item)")
            .OpenBrace()
            .AppendCode($"{sliceClassName} retVal = new {sliceClassName}(item);")
            .AppendCode($"return retVal;")
            .CloseBrace()
            ;
        }
Beispiel #8
0
        bool DefineDiscriminator(Int32 index,
                                 CodeBlockNested sliceDiscriminators,
                                 ElementDefinitionNode sliceNode,
                                 String varName,
                                 ElementDefinition.DiscriminatorComponent discriminator)
        {
            const String fcn = nameof(DefineDiscriminator);

            switch (discriminator.Type)
            {
            case ElementDefinition.DiscriminatorType.Value:
                if (DefineSliceOnValueDiscriminator(index, sliceDiscriminators, sliceNode, varName, discriminator, "valueFilterMethod", "leafType") == false)
                {
                    return(false);
                }
                return(true);

            default:
                this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: discriminator.Type {discriminator.Type} currently implemented. '{elementNode.FullPath()}'");
                return(false);
            }
        }
Beispiel #9
0
        /// <summary>
        /// Process elements, searching for elements that are sliced.
        /// </summary>
        /// <param name="sd"></param>
        /// <returns></returns>
        bool ProcessElementSlices(ElementDefinitionNode node)
        {
            //const String fcn = nameof(ProcessResourceConstraint);

            // Dont create slices on extensions. Those will be handled by another tool.
            if (node.FhirItemType == typeof(Extension))
            {
                return(false);
            }

            bool retVal = true;

            if (node.Slices.Any())
            {
                if (CreateSlice(node) == false)
                {
                    retVal = false;
                }
            }

            foreach (var child in node.ChildNodes)
            {
                if (ProcessElementSlices(child) == false)
                {
                    retVal = false;
                }
            }

            foreach (var slice in node.Slices)
            {
                if (ProcessElementSlices(slice) == false)
                {
                    retVal = false;
                }
            }
            return(retVal);
        }
Beispiel #10
0
        /// <summary>
        /// Create method to set element at indicated path to passed value.
        /// </summary>
        public bool GenerateSetElements(CodeBlockNested block,
                                        ElementDefinitionNode node,
                                        String baseName,
                                        String path,
                                        String leafNodeValue = null)
        {
            const String    fcn = nameof(GenerateSetElements);
            CodeBlockNested childBlock;

            if (block is null)
            {
                throw new ArgumentNullException(nameof(block));
            }
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            if (path is null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            void GenerateSetChildCode(ref string containerName,
                                      Type containerType,
                                      string itemName,
                                      Type itemType,
                                      String value)
            {
                if (containerName is null)
                {
                    throw new ArgumentNullException(nameof(containerName));
                }
                if (itemName is null)
                {
                    throw new ArgumentNullException(nameof(itemName));
                }

                String containerTypeName = containerType.FriendlyName();
                String itemTypeName      = itemType.FriendlyName();

                if (value == null)
                {
                    value = $"new {itemTypeName}()";
                }

                if (containerType.IsList())
                {
                    childBlock
                    .AppendCode($"if ({containerName}.Count == 0)")
                    .AppendCode($"    {containerName}.Add({value});")
                    ;
                    containerName = $"{containerName}[0].{itemName}";
                }
                else
                {
                    childBlock
                    .AppendCode($"if ({containerName}.{itemName} == null)")
                    .AppendCode($"    {containerName}.{itemName} = {value};")
                    ;
                    containerName = $"{containerName}.{itemName}";
                }
            }

            String[] pathItems = path.Split('.');
            Int32    i         = 0;

            if (pathItems[0] == node.Name)
            {
                i += 1;
            }

            childBlock = block.AppendBlock();
            String fullName = baseName;

            while (i < pathItems.Length)
            {
                String pathItem = pathItems[i];
                if (pathItem.StartsWith("resolve("))
                {
                    this.Gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else if (pathItem.StartsWith("extension(\""))
                {
                    this.Gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else if (pathItem.StartsWith("ofType("))
                {
                    this.Gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else
                {
                    if (node.TryGetAnyChild(pathItem, out ElementDefinitionNode next) == false)
                    {
                        this.Gen.ConversionError(this.GetType().Name, fcn, $"Child {pathItem} not found");
                        return(false);
                    }

                    PropertyInfo childProperty = node.FhirItemType.GetPropertyByFhirName(pathItem);
                    String       value         = null;
                    if (i == pathItems.Length - 1)
                    {
                        value = leafNodeValue;
                    }
                    GenerateSetChildCode(ref fullName, node.FhirItemType, childProperty.Name, next.FhirType, value);
                    node = next;
                }
                i += 1;
            }
            return(true);
        }
Beispiel #11
0
        /// <summary>
        /// Create slices on indicated node.
        /// </summary>
        /// <param name="elementNode">Element node containing discriminator</param>
        /// <returns></returns>
        public bool CreateSlice(ElementDefinitionNode elementNode)
        {
            CSSliceCreator c = new CSSliceCreator(this.className, this, this.subClassBlock, this.methodsBlock, elementNode, this.fhirBaseClassType);

            return(c.CreateSlice());
        }
Beispiel #12
0
        bool DefineSliceOnValueDiscriminator(Int32 index,
                                             CodeBlockNested sliceDiscriminators,
                                             ElementDefinitionNode sliceNode,
                                             String varName,
                                             ElementDefinition.DiscriminatorComponent discriminator,
                                             String valueFilterMethod,
                                             String leafType)
        {
            const String fcn = nameof(DefineSliceOnValueDiscriminator);

            var     selectedNodes = sliceNode.Select(discriminator.Path).ToArray();
            var     fixedNodes    = selectedNodes.FixedValues().ToArray();
            Element fixedValue    = fixedNodes.SingleOrDefault();

            if (fixedValue == null)
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node lacks fixed element {discriminator.Path}");
                return(false);
            }

            String sliceName = sliceNode.Element.SliceName;

            CodeBlockNested valueMethodBlock = sliceClassMethods.AppendBlock();

            valueFilterMethod = CSMisc.ValueFilterName(CSMisc.MakePath(sliceNode.SlicePath(), discriminator.Path));
            // Note: We are defining method here, after we know the return value type.
            valueMethodBlock
            .BlankLine()
            .SummaryOpen()
            .AppendCode($"/// Return all elements for discriminator # {index+1}'")
            .SummaryLines(discriminator.ToFormatedJson())
            .SummaryClose()
            ;

            {
                GenerateFhirPathSearch g = new GenerateFhirPathSearch(this.gen);
                if (g.Generate(valueMethodBlock, "static", valueFilterMethod, elementNode, discriminator.Path, out Type leaf) == false)
                {
                    return(false);
                }
                leafType = leaf.FriendlyName();
            }


            String tempVarName = $"sliceOnValueDiscriminator";

            sliceDiscriminators
            .OpenBrace()
            .AppendLine($"/// Define discriminator'")
            .AppendLines("/// ", discriminator.ToFormatedJson().ToLines())
            .AppendCode($"var {tempVarName} = new SliceOnValueDiscriminator<{baseItemTypeName}, {leafType}>()")
            .OpenBrace()
            .AppendCode($"Path = \"{discriminator.Path}\",")
            .AppendCode($"ValueFilter = {valueFilterMethod}")
            .CloseBrace(";")
            ;

            ElementFixCode.Construct(sliceDiscriminators, fixedValue, $"{tempVarName}.Pattern", out String propertyType);

            sliceDiscriminators
            .AppendCode($"{varName} = {tempVarName};")
            .CloseBrace("")
            ;

            return(true);
        }
Beispiel #13
0
        void CreateSliceAccessorClass(ElementDefinitionNode sliceNode,
                                      out String sliceClassName,
                                      out String sliceInterfaceName)
        {
            const String fcn = nameof(CreateSliceAccessorClass);

            String sliceName = sliceNode.Element.SliceName.ToMachineName();

            sliceClassName     = $"{sliceName}Impl";
            sliceInterfaceName = $"I{sliceName}";
            String sliceBaseClassName;
            String sliceBaseInterfaceName;
            String baseType = elementNode.FhirType.FriendlyName();

            // Debug.Assert(sliceClassName != "BreastradAbnormalityDensityImpl");

            switch (SliceAccessorType(sliceNode))
            {
            case SliceAccessorTypes.Error:
                sliceBaseClassName     = "??";
                sliceBaseInterfaceName = "??";
                break;

            case SliceAccessorTypes.Single:
                sliceBaseClassName     = $"SliceListAccessorSingle<{accessorType}>";
                sliceBaseInterfaceName = $"ISliceAccessorSingle<{accessorType}>";
                break;

            case SliceAccessorTypes.Multiple:
                sliceBaseClassName     = $"SliceListAccessorMultiple<{accessorType}>";
                sliceBaseInterfaceName = $"ISliceAccessorMultiple<{accessorType}>";
                break;

            default:
                throw new NotImplementedException("Unknown SliceAccessorTypes value");
            }

            String elementJson = sliceNode.Element.ToFormatedJson();

            this.subClassBlock
            .BlankLine()
            .SummaryOpen()
            .Summary($"public interface that implements the functionality of slice {sliceClassName}")
            .SummaryClose()
            .AppendCode($"public interface {sliceInterfaceName} : {sliceBaseInterfaceName}")
            .OpenBrace()
            .CloseBrace()
            .BlankLine()
            .SummaryOpen()
            .Summary($"private class that implements the functionality of slice {sliceClassName}")
            .Summary("")
            .Summary(elementJson.ToLines())
            .SummaryClose()
            .AppendCode($"class {sliceClassName} : {sliceBaseClassName}, {sliceInterfaceName}")
            .OpenBrace()
            .DefineBlock(out this.sliceStaticFields)
            .DefineBlock(out CodeBlockNested staticConstructorHeader)
            .DefineBlock(out this.sliceClassFields)
            .DefineBlock(out this.sliceClassMethods)
            .CloseBrace()
            ;

            staticConstructorHeader
            .SummaryOpen()
            .Summary("Static constructor")
            .SummaryClose()
            .AppendLine("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Performance\", \"CA1810:Initialize reference type static fields inline\")]")
            .AppendCode($"static {sliceClassName}()")
            .OpenBrace()
            .DefineBlock(out this.sliceStaticConstructor)
            .CloseBrace()
            ;

            if (sliceName == null)
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node '{elementNode.FullPath()}' lacks slice name");
                retVal = false;
            }
            else
            {
                const String sliceFieldName = "slicing";

                CreateConstructor(sliceClassName, sliceFieldName);

                this.sliceStaticFields
                .BlankLine()
                .SummaryOpen()
                .Summary($"slicing discriminator for {elementNode.FullPath()} slice {sliceName}")
                .SummaryClose()
                .AppendCode($"static Slicing<{baseItemTypeName}> {sliceFieldName};")
                ;

                this.sliceStaticConstructor
                .BlankLine()
                ;

                this.sliceStaticConstructor
                .AppendLine("// Instantiate slicing discriminator")
                .OpenBrace()
                .AppendCode($"ISliceDiscriminator<{baseItemTypeName}>[] discriminators = ")
                .AppendCode($"    new ISliceDiscriminator<{baseItemTypeName}>[{discriminators.Length}];")
                ;

                for (Int32 i = 0; i < discriminators.Length; i++)
                {
                    if (DefineDiscriminator(i, this.sliceStaticConstructor, sliceNode, $"discriminators[{i}]", discriminators[i]) == false)
                    {
                        retVal = false;
                    }
                }

                this.sliceStaticConstructor
                .AppendCode($"{sliceFieldName} = new Slicing<{baseItemTypeName}>")
                .OpenBrace()
                .AppendCode($"Discriminators = discriminators")
                .CloseBrace(";")
                .CloseBrace()
                ;
            }

            // Recursively create code to set values that are fixed in object.
            // If a child object needs to be fixed, make sure that parent objects are created
            // as well.
            // i.e. if a.b.c = fix(...)
            // than we need to create a and a.b as well as setting a.b.c.
            void SetFixedValues(ElementDefinitionNode setNode,
                                String propertyPath)
            {
                Int32 varNum = 0;

                foreach (ElementDefinitionNode setNodeChild in setNode.ChildNodes)
                {
                    String childPropertyPath = $"{propertyPath}.{setNodeChild.PropertyName}";

                    String childItemTypeName = setNodeChild.FhirItemType.FriendlyName();
                    if (setNodeChild.IsFixed)
                    {
                        if (setNodeChild.IsListType)
                        {
                            String varName = $"var{varNum}";
                            varNum += 1;
                            ElementFixCode.Construct(sliceClassMethods, setNodeChild.Element.Fixed, $"{varName}", out String propertyType);
                            sliceClassMethods.AppendCode($"{childPropertyPath}.Add({varName});");
                        }
                        else
                        {
                            ElementFixCode.Construct(sliceClassMethods, setNodeChild.Element.Fixed, childPropertyPath, out String propertyType);
                        }
                    }
                    else if (setNodeChild.HasFixedChild)
                    {
                        String varName = $"var{varNum}";
                        varNum += 1;
                        sliceClassMethods.AppendCode($"{childItemTypeName} {varName} = new {childItemTypeName}();");
                        if (setNodeChild.IsListType)
                        {
                            sliceClassMethods.AppendCode($"{childPropertyPath}.Add({varName});");
                        }
                        else
                        {
                            sliceClassMethods.AppendCode($"{childPropertyPath} = {varName};");
                        }
                        SetFixedValues(setNodeChild, varName);
                    }
                    else if (setNodeChild.HasFixedSlice)
                    {
                        String varName = $"var{varNum}";
                        varNum += 1;
                        sliceClassMethods.AppendCode($"// {childItemTypeName} {varName} = xxyyz;");
                        //methods.AppendCode($"{childItemTypeName} {varName} = new {childItemTypeName}();");
                        //if (setNodeChild.IsListType)
                        //    methods.AppendCode($"{childPropertyPath}.Add({varName});");
                        //else
                        //    methods.AppendCode($"{childPropertyPath} = {varName};");
                        //SetFixedValues(setNodeChild, varName);
                    }
                }
            }

            sliceClassMethods
            .BlankLine()
            .SummaryOpen()
            .Summary($"Create and initialize a new item")
            .SummaryClose()
            .AppendCode($"protected override {accessorType} Create()")
            .OpenBrace()
            .AppendCode($"{accessorType} retVal = new {accessorType}();")
            ;
            SetFixedValues(sliceNode, "retVal");
            sliceClassMethods
            .AppendCode($"return retVal;")
            .CloseBrace()
            ;
        }
        //$$$ Delete
        /// <summary>
        /// Traverse children using simple fhir path query.
        /// Return selected elements, or null if not found.
        /// </summary>
        public bool Generate(CodeBlockNested block,
                             String methodModifiers,
                             String methodName,
                             ElementDefinitionNode node,
                             String path,
                             out Type leafType)
        {
            const String fcn = nameof(Generate);

            if (block is null)
            {
                throw new ArgumentNullException(nameof(block));
            }
            if (methodModifiers is null)
            {
                throw new ArgumentNullException(nameof(methodModifiers));
            }
            if (methodName is null)
            {
                throw new ArgumentNullException(nameof(methodName));
            }
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            if (path is null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            //String fhirTypeName = node.FhirType.FriendlyName();
            String fhirItemTypeName = node.FhirItemType.FriendlyName();
            // we need to write header after we determine leaf node type.
            CodeBlockNested methodHeaderBlock = block.AppendBlock();

            block
            .OpenBrace()
            .BlankLine()
            ;

            childBlock = block.AppendBlock();

            String[] pathItems = path.Split('.');
            Int32    i         = 0;

            if (pathItems[0] == node.Name)
            {
                i += 1;
            }

            Int32 resultCounter = 0;

            leafType = null;
            String resultThis = "head";

            while (i < pathItems.Length)
            {
                resultCounter += 1;
                String resultNext = $"result{resultCounter}";

                String pathItem = pathItems[i++];
                if (pathItem.StartsWith("resolve("))
                {
                    this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else if (pathItem.StartsWith("extension(\""))
                {
                    this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else if (pathItem.StartsWith("ofType("))
                {
                    this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented");
                    return(false);
                }
                else
                {
                    if (node.TryGetAnyChild(pathItem, out ElementDefinitionNode next) == false)
                    {
                        this.gen.ConversionError(this.GetType().Name, fcn, $"Child {pathItem} not found");
                        return(false);
                    }

                    Type         nodeType          = node.FhirItemType;
                    PropertyInfo childProperty     = nodeType.GetPropertyByFhirName(pathItem);
                    String       childPropertyName = childProperty.Name;
                    String       childMethodName   = GenerateGetChild(childPropertyName, nodeType, childProperty.PropertyType);

                    block.AppendCode($"IEnumerable<{next.FhirItemType.FriendlyName()}> {resultNext} = {childMethodName}({resultThis});");
                    resultThis = resultNext;
                    node       = next;
                }
            }

            block
            .AppendCode($"return {resultThis};")
            .CloseBrace()
            ;

            leafType = node.FhirItemType;

            methodHeaderBlock
            .AppendCode($"{methodModifiers} IEnumerable<{leafType.FriendlyName()}> {methodName}(IEnumerable<{fhirItemTypeName}> head)")
            ;
            return(true);
        }
Beispiel #15
0
 public SDefInfo(StructureDefinition sDef)
 {
     this.SDef             = sDef;
     ElementDefinitionNode = ElementDefinitionNode.Create(sDef);
 }