Убрать теги шрифтов из XML с помощью nokogiri - PullRequest
1 голос
/ 17 сентября 2011

Я пытаюсь очистить некоторые 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 ]

1 голос
/ 20 сентября 2011

Спасибо всем за помощь.В конце я понял, как работает с этим хаком 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}
0 голосов
/ 17 сентября 2011

Если «мусор из 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>

Я не знаю, как убедить Нокогири убрать эту паузу 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) }

Я немного проверил это, но я бы порекомендовал вам немного больше протестировать его на реальных данных.

В любом случае вы теряете префиксы пространства имен ss и x; это справедливо, так как XML неправильно объявляет пространства имен, поэтому Нокогири делает вид, что их не существует. Если вам нужны пространства имен, добавьте эти атрибуты

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 не так силен; это должно сделать работу, хотя.

0 голосов
/ 17 сентября 2011

Вы можете извлечь содержимое, прежде чем удалять их следующим образом:

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

...