static void GenerateUXMLRecursive(
            VisualTreeAsset vta, string vtaPath, VisualElementAsset root,
            Dictionary <int, List <VisualElementAsset> > idToChildren,
            StringBuilder stringBuilder, int depth, bool writingToFile)
        {
            Indent(stringBuilder, depth);

            stringBuilder.Append(BuilderConstants.UxmlOpenTagSymbol);
            AppendElementTypeName(root, stringBuilder);

            // Add all non-style attributes.
            AppendElementNonStyleAttributes(root, stringBuilder, writingToFile);

            // Add style classes to class attribute.
            if (root.classes != null && root.classes.Length > 0)
            {
                stringBuilder.Append(" class=\"");
                for (int i = 0; i < root.classes.Length; i++)
                {
                    if (i > 0)
                    {
                        stringBuilder.Append(" ");
                    }

                    stringBuilder.Append(root.classes[i]);
                }
                stringBuilder.Append("\"");
            }

            // Add inline StyleSheet attribute.
            if (root.ruleIndex != -1)
            {
                if (vta.inlineSheet == null)
                {
                    Debug.LogWarning("VisualElementAsset has a RuleIndex but no inlineStyleSheet");
                }
                else
                {
                    StyleRule r = vta.inlineSheet.rules[root.ruleIndex];

                    if (r.properties != null && r.properties.Length > 0)
                    {
                        var ruleBuilder   = new StringBuilder();
                        var exportOptions = new UssExportOptions();
                        exportOptions.propertyIndent = string.Empty;
                        StyleSheetToUss.ToUssString(vta.inlineSheet, exportOptions, r, ruleBuilder);
                        var ruleStr = ruleBuilder.ToString();

                        // Need to remove newlines here before we give it to
                        // AppendElementAttribute() so we don't add "&#10;" everywhere.
                        ruleStr = ruleStr.Replace("\n", " ");
                        ruleStr = ruleStr.Replace("\r", "");
                        ruleStr = ruleStr.Trim();

                        AppendElementAttribute("style", ruleStr, stringBuilder);
                    }
                }
            }

            // If we have no children, avoid adding the full end tag and just end the open tag.
            bool hasChildTags = false;

            // Add special children.
            var styleSheets     = root.GetStyleSheets();
            var styleSheetPaths = root.GetStyleSheetPaths();

            if (styleSheetPaths != null && styleSheetPaths.Count > 0)
            {
                Assert.IsNotNull(styleSheets);
                Assert.AreEqual(styleSheetPaths.Count, styleSheets.Count);

                bool newLineAdded = false;

                for (var i = 0; i < styleSheetPaths.Count; ++i)
                {
                    var styleSheet     = styleSheets[i];
                    var styleSheetPath = styleSheetPaths[i];
                    ProcessStyleSheetPath(
                        vtaPath,
                        styleSheet, styleSheetPath, stringBuilder, depth,
                        ref newLineAdded, ref hasChildTags);
                }
            }

            var templateAsset = root as TemplateAsset;

            if (templateAsset != null && templateAsset.attributeOverrides != null && templateAsset.attributeOverrides.Count > 0)
            {
                if (!hasChildTags)
                {
                    stringBuilder.Append(BuilderConstants.UxmlCloseTagSymbol);
                    stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
                }

                var overridesMap = new Dictionary <string, List <TemplateAsset.AttributeOverride> >();
                foreach (var attributeOverride in templateAsset.attributeOverrides)
                {
                    if (!overridesMap.ContainsKey(attributeOverride.m_ElementName))
                    {
                        overridesMap.Add(attributeOverride.m_ElementName, new List <TemplateAsset.AttributeOverride>());
                    }

                    overridesMap[attributeOverride.m_ElementName].Add(attributeOverride);
                }
                foreach (var attributeOverridePair in overridesMap)
                {
                    var elementName = attributeOverridePair.Key;
                    var overrides   = attributeOverridePair.Value;

                    Indent(stringBuilder, depth + 1);
                    stringBuilder.Append(BuilderConstants.UxmlOpenTagSymbol + "AttributeOverrides");
                    AppendElementAttribute("element-name", elementName, stringBuilder);

                    foreach (var attributeOverride in overrides)
                    {
                        AppendElementAttribute(attributeOverride.m_AttributeName, attributeOverride.m_Value, stringBuilder);
                    }

                    stringBuilder.Append(" " + BuilderConstants.UxmlCloseTagSymbol);
                    stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
                }

                hasChildTags = true;
            }

            // Iterate through child elements.
            List <VisualElementAsset> children;

            if (idToChildren != null && idToChildren.TryGetValue(root.id, out children) && children.Count > 0)
            {
                if (!hasChildTags)
                {
                    stringBuilder.Append(BuilderConstants.UxmlCloseTagSymbol);
                    stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
                }

                children.Sort(VisualTreeAssetUtilities.CompareForOrder);

                foreach (var childVea in children)
                {
                    GenerateUXMLRecursive(
                        vta, vtaPath, childVea, idToChildren, stringBuilder,
                        depth + 1, writingToFile);
                }

                hasChildTags = true;
            }

            // Iterate through Uxml Objects
            var entry = vta.GetUxmlObjectEntry(root.id);

            if (entry.uxmlObjectAssets != null && entry.uxmlObjectAssets.Count > 0)
            {
                if (!hasChildTags)
                {
                    stringBuilder.Append(BuilderConstants.UxmlCloseTagSymbol);
                    stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
                }

                foreach (var childVea in entry.uxmlObjectAssets)
                {
                    GenerateUXMLRecursive(
                        vta, vtaPath, childVea, idToChildren, stringBuilder,
                        depth + 1, writingToFile);
                }

                hasChildTags = true;
            }

            if (hasChildTags)
            {
                Indent(stringBuilder, depth);
                stringBuilder.Append(BuilderConstants.UxmlOpenTagSymbol + "/");
                AppendElementTypeName(root, stringBuilder);
                stringBuilder.Append(BuilderConstants.UxmlCloseTagSymbol);
                stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
            }
            else
            {
                stringBuilder.Append(" " + BuilderConstants.UxmlEndTagSymbol);
                stringBuilder.Append(BuilderConstants.newlineCharFromEditorSettings);
            }
        }