SHARE
TWEET

Untitled

a guest Jan 19th, 2020 86 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #[derive(Clone, Debug)]
  2. pub enum NodeType {
  3.     Element,
  4.     Attribute,
  5.     Text,
  6.     Comment,
  7.     DocumentType,
  8. }
  9.  
  10. pub enum TagType {
  11.     None,
  12.     Opening,
  13.     Closing,
  14.     SelfClosing,
  15. }
  16.  
  17. #[derive(Clone, Debug)]
  18. pub struct DomElement<'a> {
  19.    children: Vec<&'a DomElement<'a>>,
  20.    parentNode: Box<Option<DomElement<'a>>>,
  21.     nodeValue: String,
  22.     nodeType: NodeType,
  23.     innerHTML: String,
  24.     outerHTML: String,
  25.     tagName: String,
  26. }
  27.  
  28. impl DomElement<'_> {
  29.    pub fn new<'a>(nodeType: NodeType) -> DomElement<'a> {
  30.        DomElement {
  31.            children: vec![],
  32.            parentNode: Box::from(None),
  33.            nodeType,
  34.            innerHTML: "".to_string(),
  35.            outerHTML: "".to_string(),
  36.            nodeValue: "".to_string(),
  37.            tagName: "".to_string(),
  38.        }
  39.    }
  40. }
  41.  
  42. const SELF_CLOSING_TAGS: &[&str] = &[
  43.    "AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK",
  44.    "MENUITEM", "META", "PARAM", "SOURCE", "TRACK", "WBR",
  45. ];
  46.  
  47. fn getTagName(source: &str) -> String {
  48.    return source
  49.        .replace("<", "")
  50.        .replace("/", "")
  51.        .replace(">", "")
  52.        .split(" ")
  53.        .collect::<Vec<&str>>()[0]
  54.        .to_uppercase()
  55.        .trim()
  56.        .to_string();
  57. }
  58.  
  59. fn getTagType(token: &str, tagName: &str) -> TagType {
  60.    let mut chars = token.chars();
  61.  
  62.    if chars.nth(0).unwrap() == '<' && chars.clone().last().unwrap() == '>' {
  63.        if chars.nth(1).unwrap() == '/' {
  64.            return TagType::Closing;
  65.        } else if SELF_CLOSING_TAGS.contains(&token) {
  66.            return TagType::SelfClosing;
  67.        } else {
  68.            return TagType::Opening;
  69.        }
  70.    }
  71.  
  72.    return TagType::None;
  73. }
  74.  
  75. fn getNodeType(token: &str, tagName: &str) -> NodeType {
  76.    let mut chars = token.chars();
  77.  
  78.    if chars.nth(0).unwrap() == '<' && chars.clone().last().unwrap() == '>' {
  79.        if token.starts_with("<!--") {
  80.            return NodeType::Comment;
  81.        } else if chars.nth(1).unwrap() == '!' {
  82.            return NodeType::DocumentType;
  83.        } else {
  84.            return NodeType::Element;
  85.        }
  86.    }
  87.  
  88.    return NodeType::Text;
  89. }
  90.  
  91. fn tokenize(html: String) -> Vec<String> {
  92.    let mut tokens: Vec<String> = vec![];
  93.  
  94.    let mut capturing = false;
  95.    let mut capturedText = String::from("");
  96.  
  97.    for i in 0..html.len() {
  98.        let c = html.chars().nth(i).unwrap();
  99.  
  100.        if c == '<' {
  101.            if capturing {
  102.                tokens.push(capturedText.to_string());
  103.            } else {
  104.                capturing = true;
  105.            }
  106.            capturedText = String::from("");
  107.        } else if c == '>' || i == html.len() - 1 {
  108.            capturing = false;
  109.            capturedText.push(c);
  110.            tokens.push(capturedText.clone());
  111.        } else if !capturing {
  112.            capturedText = String::from("");
  113.            capturing = true;
  114.        }
  115.  
  116.        if capturing {
  117.            capturedText.push(c);
  118.        }
  119.    }
  120.  
  121.    return tokens;
  122. }
  123.  
  124. fn getOpeningTag<'a>(tagName: &str, element: Option<&'a DomElement>) -> Option<&'a DomElement<'a>> {
  125.    if element.clone().unwrap().tagName == tagName {
  126.        return element;
  127.    } else {
  128.        return getOpeningTag(tagName, (*element.unwrap().parentNode).as_ref());
  129.    }
  130. }
  131.  
  132. fn build_tree<'a>(tokens: Vec<String>) -> Vec<DomElement<'a>> {
  133.    let mut elements: Vec<DomElement> = vec![];
  134.    let mut openTags: Vec<String> = vec![];
  135.  
  136.    let mut parent: Option<&DomElement> = None;
  137.  
  138.    for token in tokens {
  139.        let tagName = getTagName(&token);
  140.        let tagType = getTagType(&token, &tagName);
  141.        let nodeType = getNodeType(&token, &tagName);
  142.  
  143.        match tagType {
  144.            TagType::Closing => match parent {
  145.                Some(item) => {
  146.                    let openTagIndex = &openTags.iter().rev().position(|s| s == &tagName);
  147.                    match openTagIndex {
  148.                        Some(index) => {
  149.                            if item.tagName == tagName.to_string() {
  150.                                parent = item.parentNode.as_ref().as_ref();
  151.                            } else {
  152.                                let openingElement = getOpeningTag(&tagName, Some(item));
  153.                                match openingElement {
  154.                                    Some(el) => parent = el.parentNode.as_ref().as_ref(),
  155.                                    None => {}
  156.                                }
  157.                            }
  158.  
  159.                            openTags.remove(*index);
  160.                        }
  161.                        None => {}
  162.                    }
  163.                }
  164.                None => {}
  165.            },
  166.            _ => {
  167.                let mut element = DomElement::new(nodeType.clone());
  168.  
  169.                match parent {
  170.                    Some(item) => {
  171.                        let mut new = item.clone();
  172.                        element.parentNode = Box::from(Some(new));
  173.                        element.parentNode.unwrap().children.push(&element);
  174.                        parent = element.parentNode.as_ref().as_ref();
  175.                    }
  176.                    None => {
  177.                        elements.push(element);
  178.                    }
  179.                }
  180.  
  181.                match nodeType {
  182.                    NodeType::Element => {
  183.                        element.tagName = tagName.clone();
  184.                        openTags.push(tagName.clone());
  185.  
  186.                        match tagType {
  187.                            TagType::Opening => {
  188.                                parent = Some(&element);
  189.                            }
  190.                            _ => {}
  191.                        }
  192.                    }
  193.                    NodeType::Text => {
  194.                        element.nodeValue = token;
  195.                    }
  196.                    NodeType::Comment => {
  197.                        // TODO: getCommentText
  198.                    }
  199.                    _ => {}
  200.                }
  201.            }
  202.        }
  203.    }
  204.  
  205.    return elements;
  206. }
  207.  
  208. fn parse(html: &str) -> Vec<DomElement> {
  209.    let tokens = tokenize(html.to_string());
  210.    let elements = build_tree(tokens);
  211.  
  212.    return elements;
  213. }
  214.  
  215. fn main() {
  216.    let parsed = parse("<div>aha</div>");
  217.    println!("{:#?}", parsed);
  218. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top