使用nokogiri从XML中剥离字体标记

时间:2011-09-16 21:35:44

标签: ruby xml nokogiri

我正在尝试通过删除字体标记来清理一些xml。这就是我的开始:

<?xml version="1.0"?>
 <Worksheet ss:Name="Subtitles">
  <Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="53" x:FullColumns="1"
   x:FullRows="1" ss:DefaultRowHeight="13.5">
   <Column ss:StyleID="s62" ss:Width="80.25" ss:Span="1"/>
   <Column ss:Index="3" ss:StyleID="s63" ss:Width="249.75"/>
   <Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">00:00:11:09</Data></Cell>
    <Cell><Data ss:Type="String">00:00:13:06</Data></Cell>
    <Cell><ss:Data ss:Type="String" xmlns="http://www.w3.org/TR/REC-html40">안녕하세요<Font
       html:Face="Arial" html:Color="#000000">, </Font><Font html:Face="돋움"
       html:Color="#000000">저는</Font><Font html:Face="Arial" html:Color="#000000"> </Font><Font
       html:Face="돋움" html:Color="#000000">잭</Font><Font html:Face="Arial"
       html:Color="#000000">, 9</Font><Font html:Face="돋움" html:Color="#000000">살</Font><Font
       html:Face="Arial" html:Color="#000000"> </Font><Font html:Face="돋움"
       html:Color="#000000">입니다</Font><Font html:Face="Arial" html:Color="#000000">. </Font></ss:Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

这就是我想要的:

<?xml version="1.0"?>
 <Worksheet ss:Name="Subtitles">
  <Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="53" x:FullColumns="1"
   x:FullRows="1" ss:DefaultRowHeight="13.5">
   <Column ss:StyleID="s62" ss:Width="80.25" ss:Span="1"/>
   <Column ss:Index="3" ss:StyleID="s63" ss:Width="249.75"/>
   <Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">00:00:11:09</Data></Cell>
    <Cell><Data ss:Type="String">00:00:13:06</Data></Cell>
    <Cell><Data ss:Type="String">안녕하세요, 저는잭, 9살 입니다.</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

我正在努力用nokogiri来实现这个目标。这是我到目前为止所得到的:

require 'nokogiri'
f = File.open("junk_from_excel.xml")
doc = Nokogiri::XML(f)

# <Font html:Face="돋움" html:Color="#000000">, </Font>
doc.xpath('//@Face').each(&:remove)
# becomes: <Font html:Color="#000000">, </Font>
doc.xpath('//@Color').each(&:remove)
# becomes: <Font>, </Font>

puts doc

我不确定这有什么用处。我仍然需要转向:

<Font>, </Font>

成:

, 

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

谢谢大家的帮助。我在最后得到了这个hackish gsub的东西:

require 'nokogiri'

f = File.open("full_file_from_excel.xml")
doc = Nokogiri::XML(f)

def font_killer(children)
    children.each do |c|
        if(c.name == 'Font')
            c.replace(font_killer(c.children))
        else
            font_killer(c.children)
        end
    end
    children
end
doc = Nokogiri::XML(open('full_file_from_excel.xml').read)
doc.encoding = 'utf-8'
doc.xpath('//ss:Data[@ss:Type="String"]|//Data[@ss:Type="String"]').each { |n| font_killer(n.children) }

#save to file:
open('full_file_from_excel_fixed.xml', 'w') { |f|
  f.puts doc
}

# few more file cleanup find and replace
text = File.read("full_file_from_excel_fixed.xml")
replace = text.gsub("  </ss:Data>","</Data>")
replace = replace.gsub(" </ss:Data>","</Data>")
replace = replace.gsub("</ss:Data>","</Data>")
replace = replace.gsub("<ss:Data xmlns=\"http://www.w3.org/TR/REC-html40\" ss:Type=\"String\">", "<Data ss:Type=\"String\">")
File.open("full_file_from_excel_fixed.xml", "w") {|file| file.puts replace}

答案 1 :(得分:0)

您可以在删除内容之前提取内容,如下所示:

doc.xpath('//*[@Face]').each do |node|
  node.children.each do |child|
    node.parent << child
  end
  node.remove
end

来源:http://rubyforge.org/pipermail/nokogiri-talk/2009-June/000333.html

答案 2 :(得分:0)

如果“excel中的垃圾”很简单且ss:Type="String"元素只包含文字或<Font>废话,那么:

doc.encoding = 'utf-8'
doc.xpath('//Data[@Type="String"]').each { |n| n.content = n.text }

应该删除丑陋。这给了我这个输出:

<?xml version="1.0" encoding="utf-8"?>
<Worksheet Name="Subtitles">
  <Table ExpandedColumnCount="3" ExpandedRowCount="53" FullColumns="1" FullRows="1" DefaultRowHeight="13.5">
   <Column StyleID="s62" Width="80.25" Span="1"/>
   <Column Index="3" StyleID="s63" Width="249.75"/>
   <Row AutoFitHeight="0">
    <Cell><Data Type="String">00:00:11:09</Data></Cell>
    <Cell><Data Type="String">00:00:13:06</Data></Cell>
    <Cell><Data xmlns="http://www.w3.org/TR/REC-html40" Type="String">안녕하세요, 저는 잭, 9살 입니다. </Data></Cell>
   </Row>
  </Table>
 </Worksheet>

我不知道如何说服Nokogiri去除那个迷路xmlns

如果您不确定<Data>中的内容,那么您只能删除<Font>内容,如下所示:

def font_killer(children)
    children.each do |c|
        if(c.name == 'Font')
            c.replace(font_killer(c.children))
        else
            font_killer(c.children)
        end
    end
    children
end
doc = Nokogiri::XML(open('junk_from_excel.xml').read)
doc.encoding = 'utf-8'
doc.xpath('//Data[@Type="String"]').each { |n| font_killer(n.children) }

我对此进行了一些测试,但我建议您对实际数据进行更多测试。

在任何一种情况下,您都会丢失ssx名称空间前缀;这是公平的,因为XML没有正确声明命名空间,因此Nokogiri假装它们不存在。如果您想要名称空间,请添加这些属性

xmlns:x="urn:schemas-microsoft-com:office:excel"  
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"

<Worksheet>属性之前的ss:Name元素,然后更新XPath表达式以包含命名空间:

doc.xpath('//ss:Data[@ss:Type="String"]|//Data[@ss:Type="String"]')

可能有更好的表达方式,但我的XPath-Fu并不那么强大;那应该可以完成工作。