예제 #1
0
파일: Writer.cs 프로젝트: themotte/utils
        public string Write()
        {
            var doc = new XDocument();

            var record = new XElement("Defs");

            doc.Add(record);

            var writerContext = new WriterContext(false);

            foreach (var defObj in Database.List)
            {
                var defXml = Serialization.ComposeElement(defObj, defObj.GetType(), defObj.GetType().ComposeDefFormatted(), writerContext, isRootDef: true);
                defXml.Add(new XAttribute("defName", defObj.DefName));
                record.Add(defXml);
            }

            writerContext.DequeuePendingWrites();

            return(doc.ToString());
        }
예제 #2
0
        /// <summary>
        /// Returns a fully-formed XML document starting at an object.
        /// </summary>
        public static string Write <T>(T target, bool pretty = true)
        {
            var doc = new XDocument();

            var record = new XElement("Record");

            doc.Add(record);

            record.Add(new XElement("recordFormatVersion", 1));

            var refs = new XElement("refs");

            record.Add(refs);

            var writerContext = new WriterContext(true);

            var rootElement = Serialization.ComposeElement(target, target != null ? target.GetType() : typeof(T), "data", writerContext);

            record.Add(rootElement);

            // Handle all our pending writes
            writerContext.DequeuePendingWrites();

            // We now have a giant XML tree, potentially many thousands of nodes deep, where some nodes are references and some *should* be in the reference bank but aren't.
            // We need to do two things:
            // * Make all of our tagged references into actual references in the Refs section
            // * Tag anything deeper than a certain depth as a reference, then move it into the Refs section
            var depthTestsPending = new List <XElement>();

            depthTestsPending.Add(rootElement);

            // This is a loop between "write references" and "tag everything below a certain depth as needing to be turned into a reference".
            // We do this in a loop so we don't have to worry about ironically blowing our stack while making a change required to not blow our stack.
            while (true)
            {
                // Canonical ordering to provide some stability and ease-of-reading.
                foreach (var reference in writerContext.StripAndOutputReferences().OrderBy(kvp => kvp.Key))
                {
                    refs.Add(reference.Value);
                    depthTestsPending.Add(reference.Value);
                }

                bool found = false;
                for (int i = 0; i < depthTestsPending.Count; ++i)
                {
                    // Magic number should probably be configurable at some point
                    found |= writerContext.ProcessDepthLimitedReferences(depthTestsPending[i], 20);
                }
                depthTestsPending.Clear();

                if (!found)
                {
                    // No new depth-clobbering references found, just move on
                    break;
                }
            }

            if (refs.IsEmpty)
            {
                // strip out the refs 'cause it looks better that way :V
                refs.Remove();
            }

            return(doc.ToString());
        }