解析Html生成标签树(一)

2016-02-19 19:23 57 1 收藏

get新技能是需要付出行动的,即使看得再多也还是要动手试一试。今天图老师小编跟大家分享的是解析Html生成标签树(一),一起来学习了解下吧!

【 tulaoshi.com - Web开发 】

  解析Html成标签树结构以后,我们不但可以很容易取得想要的元素,同时也很容易将Html转换成对应的XML文件。但是由于代码是在公司写的,所以没有粘贴出来的可能性,所以我只能给出大概的代码流程,具体细节描述,相信各位都很容易写出来,并且写的比我好,关键的是算法实现思想。算法的关键如下:

  1.     Html中每个tag都是都将作为树中的一个节点存在的,每个tag都属于树中的某一层。

  2.     辅助数据结构:栈(stack)、List、HashTable。其中HashTable[i](i属于int类型)是一个List,用于临时存储第i层子Tag。

  3.     顺序扫描Html文本,当遇到”A~Z”这样的标志,表示可能是一个Tag,调用GetTag()函数对此段代码进行解析,解析出Tag名,Tag属性等等。如果返回值不为空,那么将返回值入栈。并且记录次tag的开始位置。

  4.     遇到/A~Z这样的标志,表示可能是某个Tag的结束。解析出此结束标志的Tag名。如果在栈中找到与此结束标志名同名的元素(此元素属于栈中第iLevel层),那么表示找到匹配的Tag。则Tag出栈,将HashTable[iLevel+1]到HashTable[maxLevel]中的所有元素取出作为此Tag的子节点。放入第HashTable [iLevel]中。并记录Tag的结束位置。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

  5.     对于Tagxxx/Tag之间的字符串xxx,将其作为特殊的HtmlTextTag处理。出栈,和入栈操作与普通Tag类似。

  6.     当栈为空的时候表示最后一次出栈的Tag给根节点。  由于是在公司内部开发的东西,所以不可能把源代码拿出来粘贴,所以只能把大概的代码给出。

  伪代码如下:

  view plaincopy to clipboardprint?

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

public void Parse() 
{ 
  char ch = GetCurrentChar(); //取第一个字符   
  while (!Eof()) 
  { 
    if (ch == '') 
    { 
      ch = MoveNext();   //取下一个字符   
      if ((ch = 'A') && (ch = 'Z') || (ch == '!')) 
      { 
        iBeginPos = Index;    //记录开始位置 
        //表示可能是一个标签  
        HtmlTag tag = GetTag(); //解析此Tag   
        if (tag != null) 
        { 
          //首先判断是否有文本   
          if (m_CurrentText.Lenght 0) 
          { 
            //将文本作为一个普通Tag入栈   
            Stack.Push(new HtmlTextTag(m_CurrentText)); 
          } 
          tag.BeginPos = iBeginPos;  //记录此Tag的开始位置   
          Stack.Push(tag);      //把Tag入栈   
        } 
      } 
      ch = GetCurrentChar(); 
      if (ch == '/') 
      { 
        //可能是结束标签   
        tagName = GetTagName(); 
        //从上到下查看Stack,如果Tag中存在   
        if (FindInStack(tagName)) 
        { 
          //在栈中找到名为tagName的元素,则把找到的元素出栈   
          PopTag(tagName); 
        } 
      } 
    } 
    else 
    { 
      //对于AAAxxx/AAA之间的文本xxx,这里将作为TextTag来处理  
      m_CurrentText.Append(GetCurrentChar()); 
    } 
    //继续处理下一个字符   
    ch = MoveNext(); 
  } 
  //解析完成以后,如果栈不空,那么把元素出栈,并把最后一次出栈的元素作为根   
  if (Stack.Count 0) 
  { 
    HtmlTag tag = null; 
    while (Stack.Count 0) 
    { 
      tag = Stack.Pop(); 
      PopTag(tag); 

} 
    //最后一个元素作为根元素   
    if (tag != null) 
    { 
      m_listRoot.Add(tag); 
    } 
  } 
} 
private void PopTag(HtmlTag tag) 
{ 
  int iLevel = Stack.Count; 
  //找到了元素,把iLevel到m_IMaxLevel中所有的元素按照全部作为tag的子元素   
  for (int i = iLevel + 1; i m_iMaxLevel; i++) 
  { 
    for (j = 0; j HashTable[i].Count; j++) 
    { 
      tag.Children.Add(HashTable[i][j]); 
    } 
  } 
  //表示栈已经为空,那么最后一次出栈的tag将作为根   
  if (Stack.Count == 0) 
  { 
    m_listRoot.Add(tag); 
  } 
} 
private void PopTag(string tagName) 
{ 
  /* 
   * 元素出栈的时候,首先需要把当前已经存在了的HtmlTextTag入栈 
   * 比如:A文本段1B文本段2/B文本段3/A 
   * 在Parse中,当解析出B入栈前,需要先把"文本段1"入栈 
   * 在这里,解析出了/B结束标志 
   * 那么首先需要把"文本段2"入栈。 
   * 解析出/A则需要把"文本段3'入栈。 
   * 这样才能够保证"文本段1"和"文本段3"成为A的子节点,而"文本段2"作为B的子节点 
   */ 
  if (m_CurrentText.Lenght 0) 
  { 
    //将文本作为一个普通Tag入栈   
    Stack.Push(new HtmlTextTag(m_CurrentText)); 
  } 
  HtmlTag tag = Stack.Pop(); //元素出栈   
  int iLevel = Stack.Count;  //记录栈元素数   
  while (tag.Name != tagName) 
  { 
    //将tag放入第iLevel层的List中   
    HashTable[iLevel].Add(tag); 
    tag = Stack.Pop(); 
    iLevel = Stack.Count; 
  } 
  //元素出栈后续处理   
  PopTag(tag); 
} 
private HtmlTag GetTag() 
{ 
  if ("如果发现是 !--开头的元素") //则表示是注释   
  { 
    SkipComment(); 
  } 
  HtmlTag tag = new HtmlTag(); 
  tag.Name = GetTagName(); 
  //这里的Attribute我将其作为HashTable类型,Hash[属性名]=属性值   
  tag.Attribute = GetTagAttribute(); 
  return tag; 
} 
public void Parse()
{
  char ch = GetCurrentChar(); //取第一个字符 
  while (!Eof())
  {
    if (ch == '')
    {
      ch = MoveNext();   //取下一个字符 
      if ((ch = 'A') && (ch = 'Z') || (ch == '!'))
{
        iBeginPos = Index;    //记录开始位置
        //表示可能是一个标签
        HtmlTag tag = GetTag(); //解析此Tag 
        if (tag != null)
        {
          //首先判断是否有文本 
          if (m_CurrentText.Lenght 0)
          {
            //将文本作为一个普通Tag入栈 
            Stack.Push(new HtmlTextTag(m_CurrentText));
          }
          tag.BeginPos = iBeginPos;  //记录此Tag的开始位置 
          Stack.Push(tag);      //把Tag入栈 
        }
      }
  
      ch = GetCurrentChar();
      if (ch == '/')
      {
        //可能是结束标签 
        tagName = GetTagName();
        //从上到下查看Stack,如果Tag中存在 
        if (FindInStack(tagName))
        {
          //在栈中找到名为tagName的元素,则把找到的元素出栈 
          PopTag(tagName);
        }
      }
    }
    else
    {
      //对于AAAxxx/AAA之间的文本xxx,这里将作为TextTag来处理 
      m_CurrentText.Append(GetCurrentChar());
    }
    //继续处理下一个字符 
    ch = MoveNext();
  }
  
  //解析完成以后,如果栈不空,那么把元素出栈,并把最后一次出栈的元素作为根 
  if (Stack.Count 0)
  {
    HtmlTag tag = null;
    while (Stack.Count 0)
    {
      tag = Stack.Pop();
      PopTag(tag);
    }
  
    //最后一个元素作为根元素 
    if (tag != null)
    {
      m_listRoot.Add(tag);
    }
  }
}
  
private void PopTag(HtmlTag tag)
{
  int iLevel = Stack.Count;
  
  //找到了元素,把iLevel到m_IMaxLevel中所有的元素按照全部作为tag的子元素 
  for (int i = iLevel + 1; i m_iMaxLevel; i++)
  {
    for (j = 0; j HashTable[i].Count; j++)
    {
      tag.Children.Add(HashTable[i][j]);
    }
  }
  
  //表示栈已经为空,那么最后一次出栈的tag将作为根 
  if (Stack.Count == 0)
  {
    m_listRoot.Add(tag);
}
}
  
private void PopTag(string tagName)
{
  /*
   * 元素出栈的时候,首先需要把当前已经存在了的HtmlTextTag入栈
   * 比如:A文本段1B文本段2/B文本段3/A
   * 在Parse中,当解析出B入栈前,需要先把"文本段1"入栈
   * 在这里,解析出了/B结束标志
   * 那么首先需要把"文本段2"入栈。
   * 解析出/A则需要把"文本段3'入栈。
   * 这样才能够保证"文本段1"和"文本段3"成为A的子节点,而"文本段2"作为B的子节点
   */
  if (m_CurrentText.Lenght 0)
  {
    //将文本作为一个普通Tag入栈 
    Stack.Push(new HtmlTextTag(m_CurrentText));
  }
  
  HtmlTag tag = Stack.Pop(); //元素出栈 
  int iLevel = Stack.Count;  //记录栈元素数 
  
  while (tag.Name != tagName)
  {
    //将tag放入第iLevel层的List中 
    HashTable[iLevel].Add(tag);
    tag = Stack.Pop();
    iLevel = Stack.Count;
  }
  
  //元素出栈后续处理 
  PopTag(tag);
}
  
private HtmlTag GetTag()
{
  if ("如果发现是 !--开头的元素") //则表示是注释 
  {
    SkipComment();
  }
  
  HtmlTag tag = new HtmlTag();
  tag.Name = GetTagName();
  //这里的Attribute我将其作为HashTable类型,Hash[属性名]=属性值 
  tag.Attribute = GetTagAttribute();
  return tag;
}

  解析结束以后,通过访问m_listRoot就可以遍历出所有的节点了。上面仅仅是给出了大概的方法,不过我相信要将上面的方法转换成可运行代码,各位都是有这个能力的。。。

来源:https://www.tulaoshi.com/n/20160219/1620888.html

延伸阅读
HTML指令详解 结构 <html> <head> <title>标题<title> </head> <body>..........文件内容.......... </body> </html> 1.文件标题 <title>..........</title> 2.文件更新--<meta> 【1】10秒后自动更新一次 <meta http-equiv="refresh" content=10> 【2】10秒後自动连结到另一文件 <meta htt...
表单 一、基本架构 <form action="处理资料用的CGI程式之URL"或"mailto:电子信箱的URL" method="get或post"> .......... .......... .......... </form>  二、输入文件型表单 <form action="URL" method="post"> <input> <input> .......... ..........&...
16.分隔线 <hr>  【1】分隔线的粗细 <hr size=点数>  【2】分隔线的宽度 <hr size=点数或百分比>  【3】分隔线对齐方向 <hr align="#"> #号可为 left:表向左对齐(预设值) center:表向中对齐 right:表向右对齐  【4】分隔线的颜色 <hr colo...
标签: Web开发
标签:a (标记) 说明:标明超链接的起始或目的位置。 描述: 标签属性 · accessKey 设置或获取对象的快捷键。     · atomicselection 指定元素及其内容是否可以一不可见单位统一选择。     · begin 设置或获取时间线在该元素上播放前的延迟时间。     · canHaveChildren 获取表...
标签: PHP
  <?php如何生成静态HTML   //在你的开始处加入 ob_start();  ob_start();    //以下是你的代码  //以下是你的代码  .......    //在结尾加入 ob_end_clean(),并把本页输出到一个变量中  //在结尾加入 ob_end_clean(),并把本页输出到一个变量中  $temp = ...

经验教程

838

收藏

95
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部