3
Vote

XmlCodeExporter doesn't support nested AttributeGroup references

description

Steps To Reproduce:
Try to generate data contract classes for OTA_PingRQ.xsd from OTA2005B standard (almost any other version is good to reproduce it).
 
See also: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1087778&SiteID=1
 
Workaround proposed:
update schema.AttributeGroups by adding all attributes directly from the nested AttributeGroup references
 
1) Update WebServiceCodeGenerator.GenerateDataContracts the following way.
 
...
        for (int si = 0; si < schemas.Count; si++)
        {
            XmlSchema schema = schemas[si];
 
            List<XmlSchemaAttributeGroup> processedAttributeGroups = new List<XmlSchemaAttributeGroup>();
            // -VLevchuk 2008-05-13 -added nested attribute groups workaround
            foreach (XmlSchemaAttributeGroup attributeGroup in schema.AttributeGroups.Values)
            {
                WorkaroundNestedAttributeGroupReferences(schema, attributeGroup, processedAttributeGroups);
            }
            // -VLevchuk 2008-05-13 -end of changes
...
 
2) Add WorkaroundNestedAttributeGroupReferences method
 
    private void WorkaroundNestedAttributeGroupReferences(XmlSchema schema, XmlSchemaAttributeGroup attributeGroup, List<XmlSchemaAttributeGroup> processed)
    {
        if (processed.Contains(attributeGroup))
            return;
        else
            processed.Add(attributeGroup);
 
        Log<WebServiceCodeGenerator>.Instance.DebugFormatted("Schema: {0}", schema.Id);
        Log<WebServiceCodeGenerator>.Instance.DebugFormatted("Attribute Group: {0}", attributeGroup.QualifiedName);
 
        List<XmlSchemaAttributeGroupRef> nestedReferences = new List<XmlSchemaAttributeGroupRef>();
 
        // enumerate nested attr group references
        foreach (XmlSchemaObject attr in attributeGroup.Attributes)
        {
            XmlSchemaAttributeGroupRef groupRef = attr as XmlSchemaAttributeGroupRef;
            if (groupRef != null) // nested attribute group reference!
            {
                Log<WebServiceCodeGenerator>.Instance.WarnFormatted("Nested attribute group reference. Attribute group: {0}, reference: {1}. ",
                    attributeGroup.Name, groupRef.RefName);
 
                nestedReferences.Add(groupRef);
            }
        }
 
        foreach (XmlSchemaAttributeGroupRef groupRef in nestedReferences)
        {
            XmlSchemaAttributeGroup resolved = schema.AttributeGroups[groupRef.RefName] as XmlSchemaAttributeGroup;
            if (resolved != null)
            {
                WorkaroundNestedAttributeGroupReferences(schema, resolved, processed);
 
                // Remove nested attribute group references
                attributeGroup.Attributes.Remove(groupRef);
 
                // and add resolved attributes instead. 
                foreach (XmlSchemaAttribute attribute in resolved.Attributes)
                {
                    attributeGroup.Attributes.Add(attribute); // TODO: Clone?
                }
            }
            else
            {
                string error = string.Format("Unable to resolve attribute group reference: {0} ({1}) in schema {2}. ", groupRef.RefName, groupRef.ToString(), schema.Id);
                Log<WebServiceCodeGenerator>.Instance.WarnFormatted(error);
                // TODO: throw proper exception here. 
            }
        }
    }
 
3) Logger used in the method above is log4net-like dummy class:
 
public class Log<T>
{
    private Log() { }
 
    public static readonly Log<T> Instance = new Log<T>();
 
    public void Info(string message)
    {
        Trace.WriteLine(message, "Info");
    }
 
    public void Warn(string message)
    {
        Trace.WriteLine(message, "Warn");
    }
 
    public void Error(string message)
    {
        Trace.WriteLine(message, "Error");
    }
 
    public void Debug(string message)
    {
        Trace.WriteLine(message, "Debug");
    }
 
    public void InfoFormatted(string message, params object[] args)
    {
        string msg = string.Format(message, args);
        Info(msg);
    }
 
    public void WarnFormatted(string message, params object[] args)
    {
        string msg = string.Format(message, args);
        Warn(msg);
    }
 
    public void Error(string message, Exception e)
    {
        Error(message + ". Exception text: " + e.ToString());
    }
 
    public void ErrorFormatted(string message, params object[] args)
    {
        string msg = string.Format(message, args);
        Error(msg);
    }
 
    public void DebugFormatted(string message, params object[] args)
    {
        string msg = string.Format(message, args);
        Debug(msg);
    }
}

file attachments

comments

meixger wrote Oct 8, 2012 at 1:12 PM

flatten your xsd(s)

pauljashton wrote Oct 10, 2012 at 4:56 AM

The XSDs are published by OTA (a travel industry consortium). I can't imagine they will be willing to flatten their xsds because of a problem in one particular tool.

wrote Feb 22, 2013 at 12:16 AM