Created
January 12, 2026 01:08
-
-
Save magicoal-nerb/9a094080f84799c5d0261cb5e1a100b1 to your computer and use it in GitHub Desktop.
xml in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| // Xml element | |
| public class XmlElement { | |
| // Current XML tag | |
| public string tag; | |
| // Current XML body | |
| public string body; | |
| // Current XML props | |
| public Dictionary<string, string> props; | |
| // Current Elements | |
| public List<int> elements; | |
| // Current parent | |
| public int parent; | |
| public XmlElement(string tag_, int parent_) { | |
| elements = new List<int>(); | |
| parent = parent_; | |
| props = new Dictionary<string, string>(); | |
| tag = tag_; | |
| } | |
| public float readFloat() { | |
| // Reads the current body and parses it | |
| return float.Parse(body); | |
| } | |
| }; | |
| // Reads in XML-compliant files efficiently. | |
| // Files that do not comply may output undefined behavior. | |
| public class Xml { | |
| // Holds the array portion of the xml | |
| private char[] content; | |
| // Holds the length | |
| private int length; | |
| // Used for fast substring | |
| private string data; | |
| // Current reader position | |
| private int cursor = 0; | |
| // Current element list | |
| public List<XmlElement> elements; | |
| // Current node | |
| private int node = 0; | |
| public Xml(string content_) { | |
| elements = new List<XmlElement>(); | |
| content = content_.ToCharArray(); | |
| length = content.Length; | |
| data = content_; | |
| } | |
| private void skipWhitespace() { | |
| // Skips through whitespace | |
| while(cursor < length && Char.IsWhiteSpace(content[cursor])) { | |
| cursor++; | |
| } | |
| } | |
| private string parseLiteral() { | |
| // Parses the literal | |
| int left = cursor; | |
| while(Char.IsLetterOrDigit(content[cursor]) || content[cursor] == ':') { | |
| cursor++; | |
| } | |
| return data.Substring(left, cursor - left); | |
| } | |
| private void parseClosingElement() { | |
| // We check the ending label | |
| // and go up the node. | |
| cursor++; | |
| parseLiteral(); | |
| cursor++; | |
| XmlElement currentNode = elements[node]; | |
| node = currentNode.parent; | |
| } | |
| private string parseString() { | |
| // We assume that we start off | |
| // with a open " | |
| cursor++; | |
| int left = cursor; | |
| while(cursor < length && content[cursor] != '"') { | |
| cursor++; | |
| } | |
| cursor++; | |
| return data.Substring(left, cursor - left - 1); | |
| } | |
| private void parseNewElement() { | |
| // Otherwise, we need to scan the other fields | |
| // in here! | |
| string type = parseLiteral(); | |
| int id = elements.Count; | |
| XmlElement element = new XmlElement(type, node); | |
| elements.Add(element); | |
| // Read the other props inside of the element | |
| while(content[cursor] != '>') { | |
| // Go through whitespace! | |
| skipWhitespace(); | |
| // Expects a `literal`="string" | |
| string key = parseLiteral(); | |
| cursor += 1; | |
| element.props[key] = parseString(); | |
| } | |
| // Then, if it does not start with a <, then we consider | |
| // the body of this element. | |
| cursor += 1; | |
| skipWhitespace(); | |
| if(content[cursor] == '<') { | |
| // Do not do anything; we will do this in the main loop! | |
| XmlElement parent = elements[node]; | |
| parent.elements.Add(id); | |
| node = id; | |
| return; | |
| } | |
| // Otherwise, we will keep on going until we reach the ending '>' | |
| int left = cursor; | |
| while(content[cursor] != '<') { | |
| cursor++; | |
| } | |
| // Once we do, just set the body! | |
| // We can't deliver any other nodes, so we will early exit. | |
| element.body = data.Substring(left, cursor - left); | |
| // </type> | |
| cursor += 3 + type.Length; | |
| } | |
| private void parseElement() { | |
| if(content[cursor] == '/') { | |
| parseClosingElement(); | |
| } else { | |
| parseNewElement(); | |
| } | |
| } | |
| public void parse() { | |
| // Our parser | |
| while(cursor < length) { | |
| skipWhitespace(); | |
| cursor++; | |
| parseElement(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment