SHARE
TWEET

Untitled

a guest Jan 19th, 2020 64 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 {
  19.     children: Vec<DomElement>,
  20.     parentNode: Box<Option<DomElement>>,
  21.     nodeValue: String,
  22.     nodeType: NodeType,
  23.     innerHTML: String,
  24.     outerHTML: String,
  25.     tagName: String,
  26. }
  27.  
  28. impl DomElement {
  29.     pub fn new(nodeType: NodeType) -> DomElement {
  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(tagName: &str, element: &Option<DomElement>) -> Option<DomElement> {
  125.     if element.clone().unwrap().tagName == tagName {
  126.         return element.clone();
  127.     } else {
  128.         return getOpeningTag(tagName, &(*(element.clone().unwrap()).parentNode));
  129.     }
  130. }
  131.  
  132. fn build_tree(tokens: Vec<String>) -> Vec<DomElement> {
  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 = Some((*item.parentNode.clone()).unwrap())
  151.                             } else {
  152.                                 let openingElement = getOpeningTag(&tagName, &Some(item.clone()));
  153.                                 match openingElement {
  154.                                     Some(el) => parent = Some((*el.parentNode).unwrap()),
  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(&mut item) => {
  171.                         element.parentNode = Box::from(Some(item.clone()));
  172.                         item.children.push(element.clone());
  173.                     }
  174.                     None => {
  175.                         elements.push(element.clone());
  176.                     }
  177.                 }
  178.  
  179.                 match nodeType {
  180.                     NodeType::Element => {
  181.                         element.tagName = tagName.clone();
  182.                         openTags.push(tagName.clone());
  183.  
  184.                         match tagType {
  185.                             TagType::Opening => {
  186.                                 parent = Some(element.clone());
  187.                             }
  188.                             _ => {}
  189.                         }
  190.                     }
  191.                     NodeType::Text => {
  192.                         element.nodeValue = token;
  193.                     }
  194.                     NodeType::Comment => {
  195.                         // TODO: getCommentText
  196.                     }
  197.                     _ => {}
  198.                 }
  199.             }
  200.         }
  201.     }
  202.  
  203.     return elements;
  204. }
  205.  
  206. fn parse(html: &str) -> Vec<DomElement> {
  207.     let tokens = tokenize(html.to_string());
  208.     let elements = build_tree(tokens);
  209.  
  210.     return elements;
  211. }
  212.  
  213. fn main() {
  214.     let parsed = parse("<div></div>");
  215.     println!("{:#?}", parsed);
  216. }
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