0

我正在处理非常原始的 HTML 结构,如下所示:

<a NAME="header1"></a><b><font face="Verdana, Serif"><font color="#000000"><font size=+1>Hygiene</font></font></font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Shampoo</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000"></font>Soap</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Deodorant</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Toothpaste</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000"></font>Brush</font></b> 

<a NAME="header2"></a><b><font face="Verdana, Serif"><font color="#000000"><font size=+1>Food</font></font></font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Meat</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Vegetables</font></b> 
    <p><b><font face="Verdana, Serif"><font color="#000000">Fruit</font></b> 

现在的问题是,我想从卫生标题(顶部)中获取所有项目,它们是洗发水、肥皂、除臭剂、牙膏、刷子(现在把它们放在 HashMap> 中)。

我使用这个 XPath 来获取标题(卫生和食品):

//html/body//b/font/font/font

它工作正常,我得到了我需要的东西。

然后我使用这个 XPath 来收集项目:

//html/body//p/b/font/font

对于所有项目。所以这个(最后一个)XPath 会从所有项目中返回一个列表,这些项目是 [洗发水、肥皂、除臭剂、牙膏、刷子、肉类、蔬菜、水果]。问题是我不知道什么时候停止将项目放在第一个列表中(比如,当另一个标题开始时,在这种情况下是 Food,创建新列表并将 Food 项目放在那里)。我可以使用此 XPaths 获得的只是标题(卫生、食品)和两个列表中的所有项目(不是单独的)的值。

我需要得到类似的东西:

  • 地图{“卫生”,[洗发水,肥皂,除臭剂,牙膏,刷子]}
  • 地图{“食物”,[肉类、蔬菜、水果]}

所有项目都像这样抛出,它们不在单独的 div 或 span 中,以便我可以识别新标题何时出现。

谢谢!

4

2 回答 2

1

我将首先 (a) 使用(例如)TagSoup 将其转换为 XML,然后 (b) 使用 XSLT 2.0 转换将其向上转换为更卫生的 XML 结构。

我不确定 TagSoup 到底会做什么,但如果我们假设它唯一要做的就是关闭 p 标签(</p>出现在 之后</b>),那么步骤 (b) 非常简单:

<xsl:for-each-group select="//body/*" group-starting-with="a">
  <section name="current-group()[self::b]">
    <xsl:for-each select="current-group()[self::p]">
       <item><xsl:value-of select="."/></item>
    </xsl:for-each>
  </section>
</xsl:for-each-group>

这会给你类似的东西

<section name="Hygiene">
  <item>Shampoo</item>
  <item>Soap</item>
  <item>Toothpaste</item>
</section>
<section name="Food">
  <item>Meat</item>
  <item>Veg</item>
</section>

这样就更容易玩了。

通常,当您收到这样的结构不佳的输入时,最好使用管道方法,首先清理它,然后查询它以获得您想要的信息。

于 2012-06-19T08:34:15.343 回答
0

解析这个 HTML 并不容易,因为它不适合解析(从<font>标签来看,你可能也可以使用一些丰富多彩的语言)。

AFAIK 没有办法在 XPath 中表达“在 X 之前跟随兄弟姐妹”条件,所以这里有一个替代方案:使用一个同时匹配标题和项目的 XPath 表达式,例如,您可以使用这个特定的标记

//body//font/child::text()

这将选择所有文本节点(“卫生”、“洗发水”、“肥皂”……)。

节点将按文档顺序返回(这非常重要),因此之后您可以遍历结果并对每个结果进行测试以确定它是标题还是项目(在这种情况下,您可以检查父节点是否为<font>具有size属性的元素)。

这样,您可以保留对找到的最后一个“标题”的引用,并将所有后续“项目”添加到它下面的适当数据结构中,直到遇到下一个标题等。

于 2012-06-19T08:07:40.893 回答