节点的XPath索引

时间:2012-06-19 07:38:39

标签: java javascript xslt xpath

我正在处理非常原始的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> 

现在的事情是,我想从Hygiene标题(顶部)获得所有物品,这些物品是洗发水,肥皂,除臭剂,牙膏,刷子(并且现在将它们放在HashMap&gt;中)。

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

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

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

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

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

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

我需要得到类似的东西:

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

所有项目都是这样抛出的,并且它们不在单独的div或跨度中,以便我能够识别新标题何时出现。

谢谢!

2 个答案:

答案 0 :(得分: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>

然后更容易玩。

一般来说,当您输入结构不合理的输入时,最好先使用管道方法进行清理,然后查询它以获取所需信息。

答案 1 :(得分:0)

解析这个HTML并不容易,因为它不适合解析(从<font>标签来判断你可能会使用一些关于它的彩色语言)。

AFAIK没有办法在XPath中表达“跟随兄弟姐妹直到X”的情况,所以这里有另一种选择:使用一个 XPath表达式来匹配标题和项目,例如使用这个特定的标记你可以使用

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

将选择所有文本节点(“Hygiene”,“Shampoo”,“Soap”,......)。

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

通过这种方式,您可以保留对找到的最后一个“标题”的引用,并将所有后续“项目”添加到其下的相应数据结构中,直到您遇到下一个标题等。