4

XPathエキスパートにとって簡単なポイントは次のとおりです。:)

ドキュメントの構造:

<tokens>
  <token>
    <word>Newt</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Gingrich</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>admires</word><entityType>VERB</entityType>
  </token>
  <token>
    <word>Garry</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Trudeau</word><entityType>PROPER_NOUN</entityType>
  </token>
</tokens>

ドキュメントの意味論的可能性を無視して、[["Newt"、 "Gingrich"]、["Garry"、 "Trudeau"]]を引き出したい、つまり、entityTypesがPROPER_NOUNである2つのトークンが行にある場合、これら2つのトークンから単語を抽出したいと思います。

私は次のようになりました:

"//token[entityType='PROPER_NOUN']/following-sibling::token[1][entityType='PROPER_NOUN']"

...これは2つの連続するPROPER_NOUNトークンの2番目を見つけるところまで到達しますが、最初のトークンを一緒に発行する方法がわかりません。

いくつかのメモ:

  • 問題が単純化されれば、NodeSetの高レベルの処理(Ruby / Nokogiriなど)を実行してもかまいません。
  • 3つ以上の連続したPROPER_NOUNトークン(A、B、Cと呼びます)がある場合、理想的には[A、B]、[B、C]を発行したいと思います。

アップデート

これが、高レベルのRuby関数を使用した私のソリューションです。しかし、私はXPathのいじめっ子が私の顔に砂を蹴るのにうんざりしていて、REAL XPathコーダーがそれを行う方法を知りたいです!

def extract(doc)
  names = []
  sentences = doc.xpath("//tokens")
  sentences.each do |sentence| 
    tokens = sentence.xpath("token")
    prev = nil
    tokens.each do |token|
      name = token.xpath("word").text if token.xpath("entityType").text == "PROPER_NOUN"
      names << [prev, name] if (name && prev)
      prev = name
    end
  end
  names
end
4

4 に答える 4

1

このXPath1.0式

   /*/token
      [entityType='PROPER_NOUN'
     and
       following-sibling::token[1]/entityType = 'PROPER_NOUN'
      ]
       /word

すべての「ペアの最初の名詞-単語」を選択します

このXPath式

/*/token
  [entityType='PROPER_NOUN'
 and
   preceding-sibling::token[1]/entityType = 'PROPER_NOUN'
  ]
   /word

すべての「ペアの2番目の名詞-単語」を選択します

生成された2つの結果ノードセットのそれぞれのk番目のノードを使用して実際のペアを生成する必要があります。

XSLTベースの検証

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "/*/token
      [entityType='PROPER_NOUN'
     and
       following-sibling::token[1]/entityType = 'PROPER_NOUN'
      ]
       /word
  "/>
==============
  <xsl:copy-of select=
   "/*/token
      [entityType='PROPER_NOUN'
     and
       preceding-sibling::token[1]/entityType = 'PROPER_NOUN'
      ]
       /word
  "/>
 </xsl:template>
</xsl:stylesheet>

2つのXPath式を評価し、これら2つの評価の結果を出力するだけです(適切な区切り文字を使用して、最初の結果の終わりと2番目の結果の始まりを視覚化します)。

提供されたXMLドキュメントに適用する場合:

<tokens>
  <token>
    <word>Newt</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Gingrich</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>admires</word><entityType>VERB</entityType>
  </token>
  <token>
    <word>Garry</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Trudeau</word><entityType>PROPER_NOUN</entityType>
  </token>
</tokens>

出力は次のとおりです。

<word>Newt</word>
<word>Garry</word>
==============
  <word>Gingrich</word>
<word>Trudeau</word>

2つの結果(お気に入りのPLで指定します)の組み合わせ(圧縮)は次のとおりです。

["Newt", "Gingrich"]

["Garry", "Trudeau"]

同じ変換がこのXMLドキュメントに適用される場合(3つあることに注意してください):

<tokens>
  <token>
    <word>Newt</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Gingrich</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Rep</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>admires</word><entityType>VERB</entityType>
  </token>
  <token>
    <word>Garry</word><entityType>PROPER_NOUN</entityType>
  </token>
  <token>
    <word>Trudeau</word><entityType>PROPER_NOUN</entityType>
  </token>
</tokens>

結果は次のようになります

<word>Newt</word>
<word>Gingrich</word>
<word>Garry</word>
==============
  <word>Gingrich</word>
<word>Rep</word>
<word>Trudeau</word>

2つの結果を圧縮すると、正しい、必要な最終結果が生成されます。

["Newt", "Gingrich"],

["Gingrich", "Rep"],

["Garry", "Trudeau"]

必要な結果は、単一のXPath2.0式を使用して生成できます。XPath 2.0ソリューションに興味がある場合は、お知らせください。

于 2012-09-15T05:19:23.273 に答える
1

これは2つのステップで行います。最初のステップは、ノードのセットを選択することです。

//token[entityType='PROPER_NOUN' and following-sibling::token[1][entityType='PROPER_NOUN']]

tokenこれにより、2ワードのペアを開始するすべてのが得られます。次に、実際のペアを取得するには、ノードリストを繰り返し処理し、抽出./wordしてfollowing-sibling::token[1]/word

XmlStarlet(http://xmlstar.sourceforge.net/-迅速なxml操作のための素晴らしいツール)を使用すると、コマンドラインは次のようになります。

xml sel -t -m "//token[entityType='PROPER_NOUN' and following-sibling::token[1][entityType='PROPER_NOUN']]" -v word -o "," -v "following-sibling::token[1]/word" -n /tmp/tok.xml 

与える

Newt,Gingrich
Garry,Trudeau

XmlStarletは、そのコマンドラインをxsltにコンパイルします。関連するビットは次のとおりです。

  <xsl:for-each select="//token[entityType='PROPER_NOUN' and following-sibling::token[1][entityType='PROPER_NOUN']]">
    <xsl:value-of select="word"/>
    <xsl:value-of select="','"/>
    <xsl:value-of select="following-sibling::token[1]/word"/>
    <xsl:value-of select="'&#10;'"/>
  </xsl:for-each>

Nokogiriを使用すると、次のようになります。

#parse the document
doc = Nokogiri::XML(the_document_string)

#select all tokens that start 2-word pair
pair_starts = doc.xpath '//token[entityType = "PROPER_NOUN" and following-sibling::token[1][entityType = "PROPER_NOUN"]]'

#extract each word and the following one
result = pair_starts.each_with_object([]) do |node, array|
  array << [node.at_xpath('word').text, node.at_xpath('following-sibling::token[1]/word').text]
end
于 2012-09-14T23:10:58.093 に答える
0

XPathはノードまたはノードセットを返しますが、グループは返しません。したがって、各グループの開始を識別してから、残りを取得する必要があります。

first = "//token[entityType='PROPER_NOUN' and following-sibling::token[1][entityType='PROPER_NOUN']]/word"
next = "../following-sibling::token[1]/word"

doc.xpath(first).map{|word| [word.text, word.xpath(next).text] }

出力:

[["Newt", "Gingrich"], ["Garry", "Trudeau"]]
于 2012-09-15T00:12:54.423 に答える
0

XPathだけでは、このタスクには十分な能力がありません。しかし、XSLTでは非常に簡単です。

<xsl:for-each-group select="token" group-adjacent="entityType">
  <xsl:if test="current-grouping-key="PROPER_NOUN">
     <xsl:copy-of select="current-group">
     <xsl:text>====</xsl:text>
  <xsl:if>
</xsl:for-each-group>
于 2012-09-15T18:20:16.657 に答える