chell chell - 1 month ago 5
Ruby Question

How to extract element with an ID that has text of two words length using Nokogiri

I have an XML file as follows:

<w:p w14:paraId="646BED8B" w14:textId="30F19BEA" w:rsidR="00CA7979" w:rsidRDefault="00197F7D">
<w:r>
<w:t xml:space="preserve">This </w:t>
</w:r>
<w:r w:rsidR="00656E17">
<w:t xml:space="preserve">first sentence </w:t>
</w:r>
<w:ins w:author="Mitchell Gould" w:date="2016-10-04T16:15:00Z" w:id="0">
<w:r w:rsidR="00E24CA3">
<w:t>is</w:t>
</w:r>
</w:ins>
<w:del w:author="Mitchell Gould" w:date="2016-10-04T16:15:00Z" w:id="1">
<w:r w:rsidDel="00E24CA3" w:rsidR="00656E17">
<w:delText>was</w:delText>
</w:r>
</w:del>
<w:r>
<w:t xml:space="preserve">for checking the verb usage errors. I will</w:t>
</w:r>
<w:ins w:author="Mitchell Gould" w:date="2016-10-04T16:18:00Z" w:id="2">
<w:r w:rsidR="00BF77BA">
<w:t xml:space="preserve">write</w:t>
</w:r>
</w:ins>
<w:del w:author="Mitchell Gould" w:date="2016-10-04T16:18:00Z" w:id="3">
<w:r w:rsidDel="00BF77BA">
<w:delText xml:space="preserve">make</w:delText>
</w:r>
</w:del>
<w:r>
<w:t xml:space="preserve">some </w:t>
</w:r>
<w:r w:rsidR="00BF77BA">
<w:t xml:space="preserve"/>
</w:r>
<w:r>
<w:t>changes</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">to the verbs and check it if the verbs </w:t>
</w:r>
<w:ins w:author="Mitchell Gould" w:date="2016-10-04T16:15:00Z" w:id="4">
<w:r w:rsidR="00E24CA3">
<w:t>are</w:t>
</w:r>
</w:ins>
<w:del w:author="Mitchell Gould" w:date="2016-10-04T16:15:00Z" w:id="5">
<w:r w:rsidDel="00E24CA3">
<w:delText>is</w:delText>
</w:r>
</w:del>
<w:r>
<w:t xml:space="preserve">fixed.</w:t>
</w:r>
</w:p>


I have an array of verbs:

@verbs = ["is", "will", "write", "are", "should", "be", "will", "add", "see", "adding", "is", "should", "be", "inserted", "will", "delete", "view", "deleting", "works", "should", "be", "deleted", "tests", "adding", "should", "be", "was", "will", "make", "is", "should", "be", "will", "adding", "should", "be", "inserted", "will", "delete", "remove", "see", "deleting", "works", "working", "should", "be", "deleted", "test", "adding", "should", "be"]


I can get all of the elements with an w:id as follows:

@elements = @file.xpath('//*[@w:id]')


However, what I want to do is get only the elements in the file that match the following:


  1. The text is 2 words or less

  2. One of the words is included in my @verbs array.



Can I do this with Nokogiri and if so how?

Answer

The easiest way is to mix in a bit of Ruby as well:

@file.xpath('//*[@w:id]').select { |node|
  words = node.text.split
  words.length <= 2 && words.any? { |word| @verbs.include?(word) }
}

EDIT: It just occurred to me, if you have more than a few words to check, you'd be much happier by converting @verbs to a set:

require 'set'
@verbset = Set.new(@verbs)

and then checking @verbset.include(word), as it is much faster than testing for membership in an array.

Comments