2014-02-20 78 views
1

使用Nokogiri :: XML :: Builder時,我需要能夠生成一個節點,該節點也可以用其他XML替換文本上的正則表達式匹配。Nokogiri Builder:用RegEx替換XML匹配

目前我能夠在節點內添加額外的XML。這是一個例子。

def xml 
    Nokogiri::XML::Builder.new do |xml| 
    xml.chapter { 
     xml.para { 
     xml.parent.add_child("Testing[1] footnote paragraph.") 
     add_footnotes(xml, 'An Entry') 
     } 
    } 
    end.to_xml 
end 

# further child nodes WILL be added to footnote 
def add_footnotes(xml, text) 
    xml.footnote text 
end 

它產生;

<chapter> 
    <para>Testing[1] footnote paragraph.<footnote>An Entry</footnote></para> 
</chapter> 

但我需要能夠運行一個正則表達式的參考[1]替換,隨着XML <footnote>替換它,產生的輸出如下;

<chapter> 
    <para>Testing<footnote>An Entry</footnote> footnote paragraph.</para> 
</chapter> 

我在這裏做出假定add_footnotes方法將接收的參考匹配(例如,如$1),其將用於從一個集合拉相應的腳註。

該方法也會添加額外的子節點,如下所示;

​​

任何人都可以幫忙嗎?

回答

0

下面是代碼中的一段代碼,展示瞭如何生成輸出。你需要把它改裝自己的代碼....

require 'nokogiri' 

FOOTNOTES = { 
    '1' => 'An Entry' 
} 
child_text = "Testing[1] footnote paragraph." 

pre_footnote, footnote_id, post_footnote = /^(.+)\[(\d+)\](.+)/.match(child_text).captures 

doc = Nokogiri::XML::Builder.new do |xml| 
    xml.chapter { 
    xml.para { 
     xml.text(pre_footnote) 
     xml.footnote FOOTNOTES[footnote_id] 
     xml.text(post_footnote) 
    } 
    } 
end 
puts doc.to_xml 

,輸出:

<?xml version="1.0"?> 
<chapter> 
    <para>Testing<footnote>An Entry</footnote> footnote paragraph.</para> 
</chapter> 

關鍵是你必須抓住文本前面和後面的目標,所以你可以插入那些作爲文本節點。然後你可以找出需要添加的東西。爲了清楚你的代碼,你應該預處理所有的文本,找出你的變量,然後落入XML生成器。不要嘗試在Builder塊內進行任何計算,而只是引用變量。如果有幫助的話,可以將構建器看作MVC類型應用程序中的視圖。

FOOTNOTES實際上可能是數據庫查找,散列或其他數據容器。


你也應該看看<<方法,它可以讓你注入XML數據源,所以你可以預先建立的腳註XML,然後遍歷包含各種腳註數組,並注入他們。通常預處理更容易,然後使用gsub將諸如[1]之類的內容視爲佔位符。見"gsub(pattern, hash) → new_str"文檔中,這個例子一起:

'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*') #=> "h3ll*" 

例如:

require 'nokogiri' 

text = 'this is[1] text and[2] text' 
footnotes = { 
    '[1]' => 'some', 
    '[2]' => 'more' 
} 

footnotes.keys.each do |k| 
    v = footnotes[k] 
    footnotes[k] = "<footnote>#{ v }</footnote>" 
end 
replacement_xml = text.gsub(/\[\d+\]/, footnotes) # => "this is<footnote>some</footnote> text and<footnote>more</footnote> text" 

doc = Nokogiri::XML::Builder.new do |xml| 
    xml.chapter { 
    xml.para { xml.<<(replacement_xml) } 
    } 
end 
puts doc.to_xml 

# >> <?xml version="1.0"?> 
# >> <chapter> 
# >> <para>this is<footnote>some</footnote> text and<footnote>more</footnote> text</para> 
# >> </chapter> 
+0

我確實考慮過拆分選項,但想通一旦我們有幾個腳註參考文件,最終可能會變得非常混亂。我認爲在任何一個段落中都有不止一個,但我仍然會等待有人在接受之前有更好的解決方案。謝謝錫人。 –

+0

查看已添加的示例。 –

+0

這裏有點嚼。這裏遲到了,所以我會在早上經歷這個。 –

0

我可以嘗試如下:

require 'nokogiri' 

def xml 
    Nokogiri::XML::Builder.new do |xml| 
    xml.chapter { 
     xml.para { 
     xml.parent.add_child("Testing[1] footnote paragraph.") 
     add_footnotes(xml, 'add text',"[1]") 
     } 
    } 
    end.to_xml 
end 

def add_footnotes(xml, text,ref) 
    string = xml.parent.child.content 
    xml.parent.child.content = "" 
    string.partition(ref).each do |txt| 
    next xml.text(txt) if txt != ref 
    xml.footnote text 
    end 
end 

puts xml 
# >> <?xml version="1.0"?> 
# >> <chapter> 
# >> <para>Testing<footnote>add text</footnote> footnote paragraph.</para> 
# >> </chapter> 
+0

當我用多個腳註引用(使用.scan來收集它們)嘗試此操作時,輸出變得混亂(不確定它是否我做錯了)。它遲到了,所以我會在早上再試一次。 –

+0

@MichaelCook我也會編輯答案,我錯過了。請稍後再看看。建議我是否需要更改。我會更新它。雖然你的帖子非常好。我有一些混亂。但讓我完成它,然後檢查和評論進一步的變化。 –

+0

好的,我正在掃描文本以收集所有參考文獻,然後對這些參考文獻進行迭代; 'references_found_by_scan.each {| ref | ...}'在其中運行'string.partition(ref).each'代碼。這雖然是重複的文本的一部分,我不知道如何防止這一點。我希望這很清楚。 –