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> 

ここで、Hygiene ヘッダー (上部) からすべての項目 (シャンプー、石鹸、デオドラント、歯磨き粉、ブラシ) を取得したいと考えています (ここではそれらを HashMap> に入れます)。

この XPath を使用してヘッダー (Hygiene と Food) を取得します。

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

そしてそれはうまくいきます、私は必要なものを手に入れます。

次に、この XPath を使用してアイテムを収集します。

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

すべてのアイテム。したがって、この (最後の) XPath は、[シャンプー、石鹸、デオドラント、歯磨き粉、ブラシ、肉、野菜、果物] のすべての項目からリストを返します。問題は、最初のリストにアイテムを配置するのをいつ停止するかがわからないことです (別のヘッダーが開始されたとき、この場合は Food で、新しいリストを作成してそこに Food アイテムを配置するなど)。この XPath で取得できるのは、ヘッダー (Hygiene、Food) の値と、両方のリスト (個別ではない) のすべての項目だけです。

次のようなものを取得する必要があります。

  • Map{"衛生", [シャンプー、石鹸、デオドラント、歯磨き粉、ブラシ]}
  • Map{"食品", [肉、野菜、果物]}

すべてのアイテムはこのようにスローされ、個別の div またはスパンにはないため、新しいヘッダーがいつ発生したかを認識できます。

ありがとう!

4

2 に答える 2

1

まず、(a) (たとえば) TagSoup を使用してこれを XML に変換し、次に (b) これをより適切な XML 構造にアップコンバートする XSLT 2.0 変換を使用します。

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>タグから判断すると、おそらくそれについていくつかのカラフルな言語を使用することもできます)。

私の知る限り、XPath で「X まで兄弟をフォロー」条件を表現する方法はありません。そのため、別の方法があります。たとえば、この特定のマークアップを使用して、ヘッダーとアイテムの両方に一致する1 つのXPath 式を使用します。

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

これにより、すべてのテキスト ノード (「衛生」、「シャンプー」、「石鹸」など) が選択されます。

ノードはドキュメント順に返されるため (これは非常に重要です)、後で結果を反復処理し、それぞれに対してテストを実行して、それがヘッダーかアイテムかを判断できます (この場合、親が属性<font>を持つ要素)。size

このようにして、最後に見つかった「ヘッダー」への参照を保持し、次のヘッダーなどに遭遇するまで、後続のすべての「アイテム」をその下の適切なデータ構造に追加できます。

于 2012-06-19T08:07:40.893 に答える