public IAttributeGroupDefinition Get(IMappedIdentifier identifier)
        {
            if (!cache.ContainsKey(identifier))
            {
                lock (cacheLock)
                {
                    if (!cache.ContainsKey(identifier))
                    {
                        cache.Add(identifier, new Lazy <IAttributeGroupDefinition>(() =>
                        {
                            //look for the tab in the XML, this is kind of dodgy as we don't handle the tab being on multiple doc types, ie: it's not handling the tab hierarchy
                            var group = (from tabs in xml.Descendants("Tabs")
                                         from tab in tabs.Elements("Tab")
                                         where (string)tab.Element("Caption") == identifier.Value
                                         select tab).FirstOrDefault();

                            //if we didn't find the group we're going to use the generic one
                            if (group == default(XElement))
                            {
                                return(Get(genericGroupId));
                            }

                            //parse the XML into a simple group object
                            var t = new AttributeGroupDefinition()
                            {
                                Id    = identifier,
                                Alias = identifier.ValueAsString,
                                Name  = group.Descendants("Caption").First().Value
                            };

                            return(t);
                        }));
                    }
                }
            }

            return(cache[identifier].Value);
        }
        public IAttributeDefinition Get(IMappedIdentifier identifier)
        {
            if (!cache.ContainsKey(identifier))
            {
                lock (cacheLock)
                {
                    if (!cache.ContainsKey(identifier))
                    {
                        cache.Add(identifier, new Lazy <IAttributeDefinition>(() => {
                            var propertyPath = identifier.Value;

                            //the ID is actually a path, ie: DocTypeAlias/PropertyAlias so we can resolve it that way
                            var propertyAsXml = xml
                                                .Descendants("DocumentType").First(x => (string)x.Element("Info").Element("Alias") == propertyPath.Split('/')[0])
                                                .Descendants("GenericProperty").First(x => (string)x.Element("Alias") == propertyPath.Split('/')[1]);

                            //find the data type
                            var dataTypeId = dataTypeRepo.ResolveIdentifier((string)propertyAsXml.Element("Type"));
                            var dataType   = dataTypeRepo.Get(dataTypeId);

                            //create an AttributeDefinition
                            //TODO: How do we do the "UI" data?
                            var attrDef           = new AttributeDefinition();
                            attrDef.Id            = identifier;
                            attrDef.AttributeType = dataType;
                            attrDef.Alias         = (string)propertyAsXml.Element("Alias");
                            attrDef.Name          = (string)propertyAsXml.Element("Name");

                            return(attrDef);
                        }));
                    }
                }
            }

            return(cache[identifier].Value);
        }