docx 0.2.03 → 0.2.07
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +51 -11
- data/lib/docx/containers.rb +2 -1
- data/lib/docx/containers/paragraph.rb +46 -3
- data/lib/docx/containers/table.rb +51 -0
- data/lib/docx/containers/table_cell.rb +39 -0
- data/lib/docx/containers/table_column.rb +29 -0
- data/lib/docx/containers/table_row.rb +28 -0
- data/lib/docx/containers/text_run.rb +25 -3
- data/lib/docx/document.rb +78 -17
- data/lib/docx/elements/bookmark.rb +3 -1
- data/lib/docx/elements/element.rb +25 -1
- data/lib/docx/elements/text.rb +5 -1
- data/lib/docx/version.rb +1 -1
- metadata +37 -38
- checksums.yaml +0 -15
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/docx/parser.rb +0 -46
- metadata.gz.sig +0 -3
data/README.md
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# docx
|
2
2
|
|
3
|
-
|
3
|
+
A ruby library/gem for interacting with `.docx` files. currently capabilities include reading paragraphs/bookmarks, inserting text at bookmarks, reading tables/rows/columns/cells and saving the document.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Usage
|
6
6
|
|
7
|
-
###
|
7
|
+
### Install
|
8
8
|
|
9
|
-
|
9
|
+
Requires ruby (tested with 2.1.1)
|
10
10
|
|
11
|
-
gem
|
11
|
+
gem 'docx', '~> 0.2.07', :require => ["docx"]
|
12
12
|
|
13
|
-
###
|
13
|
+
### Reading
|
14
14
|
|
15
15
|
``` ruby
|
16
16
|
require 'docx'
|
@@ -29,7 +29,48 @@ doc.bookmarks.each_pair do |bookmark_name, bookmark_object|
|
|
29
29
|
end
|
30
30
|
```
|
31
31
|
|
32
|
-
###
|
32
|
+
### Rendering html
|
33
|
+
``` ruby
|
34
|
+
require 'docx'
|
35
|
+
|
36
|
+
# Retrieve and display paragraphs as html
|
37
|
+
doc = Docx::Document.open('example.docx')
|
38
|
+
doc.paragraphs.each do |p|
|
39
|
+
puts p.to_html
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
### Reading tables
|
44
|
+
|
45
|
+
``` ruby
|
46
|
+
require 'docx'
|
47
|
+
|
48
|
+
# Create a Docx::Document object for our existing docx file
|
49
|
+
doc = Docx::Document.open('tables.docx')
|
50
|
+
|
51
|
+
first_table = doc.tables[0]
|
52
|
+
puts first_table.row_count
|
53
|
+
puts first_table.column_count
|
54
|
+
puts first_table.rows[0].cells[0].text
|
55
|
+
puts first_table.columns[0].cells[0].text
|
56
|
+
|
57
|
+
# Iterate through tables
|
58
|
+
doc.tables.each do |table|
|
59
|
+
table.rows.each do |row| # Row-based iteration
|
60
|
+
row.cells.each do |cell|
|
61
|
+
puts cell.text
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
table.columns.each do |column| # Column-based iteration
|
66
|
+
column.cells.each do |cell|
|
67
|
+
puts cell.text
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
### Writing
|
33
74
|
|
34
75
|
``` ruby
|
35
76
|
require 'docx'
|
@@ -38,7 +79,7 @@ require 'docx'
|
|
38
79
|
doc = Docx::Document.open('example.docx')
|
39
80
|
|
40
81
|
# Insert a single line of text after one of our bookmarks
|
41
|
-
doc.bookmarks['example_bookmark'].
|
82
|
+
doc.bookmarks['example_bookmark'].insert_text_after("Hello world.")
|
42
83
|
|
43
84
|
# Insert multiple lines of text at our bookmark
|
44
85
|
doc.bookmarks['example_bookmark_2'].insert_multiple_lines_after(['Hello', 'World', 'foo'])
|
@@ -47,7 +88,7 @@ doc.bookmarks['example_bookmark_2'].insert_multiple_lines_after(['Hello', 'World
|
|
47
88
|
doc.save('example-edited.docx')
|
48
89
|
```
|
49
90
|
|
50
|
-
###
|
91
|
+
### Advanced
|
51
92
|
|
52
93
|
``` ruby
|
53
94
|
require 'docx'
|
@@ -69,9 +110,8 @@ p_child = p_element.at_xpath("//child::*") # selects first child
|
|
69
110
|
|
70
111
|
### todo
|
71
112
|
|
72
|
-
* Add better formatting identification for specific nodes and other formatting indicators (text size, paragraph spacing)
|
73
113
|
* Calculate element formatting based on values present in element properties as well as properties inherited from parents
|
74
114
|
* Default formatting of inserted elements to inherited values
|
75
115
|
* Implement formattable elements.
|
76
116
|
* Implement styles.
|
77
|
-
* Easier multi-line text insertion at a single bookmark (inserting paragraph nodes after the one containing the bookmark)
|
117
|
+
* Easier multi-line text insertion at a single bookmark (inserting paragraph nodes after the one containing the bookmark)
|
data/lib/docx/containers.rb
CHANGED
@@ -8,13 +8,18 @@ module Docx
|
|
8
8
|
include Container
|
9
9
|
include Elements::Element
|
10
10
|
|
11
|
-
|
11
|
+
def self.tag
|
12
|
+
'p'
|
13
|
+
end
|
14
|
+
|
12
15
|
|
13
16
|
# Child elements: pPr, r, fldSimple, hlink, subDoc
|
14
17
|
# http://msdn.microsoft.com/en-us/library/office/ee364458(v=office.11).aspx
|
15
|
-
def initialize(node)
|
18
|
+
def initialize(node, document_properties = {})
|
16
19
|
@node = node
|
17
20
|
@properties_tag = 'pPr'
|
21
|
+
@document_properties = document_properties
|
22
|
+
@font_size = @document_properties[:font_size]
|
18
23
|
end
|
19
24
|
|
20
25
|
# Set text of paragraph
|
@@ -36,17 +41,55 @@ module Docx
|
|
36
41
|
text_runs.map(&:text).join('')
|
37
42
|
end
|
38
43
|
|
44
|
+
# Return paragraph as a <p></p> HTML fragment with formatting based on properties.
|
45
|
+
def to_html
|
46
|
+
html = ''
|
47
|
+
text_runs.each do |text_run|
|
48
|
+
html << text_run.to_html
|
49
|
+
end
|
50
|
+
styles = { 'font-size' => "#{font_size}pt" }
|
51
|
+
styles['text-align'] = alignment if alignment
|
52
|
+
html_tag(:p, content: html, styles: styles)
|
53
|
+
end
|
54
|
+
|
55
|
+
|
39
56
|
# Array of text runs contained within paragraph
|
40
57
|
def text_runs
|
41
|
-
@node.xpath('w:r').map {|r_node| Containers::TextRun.new(r_node) }
|
58
|
+
@node.xpath('w:r|w:hyperlink/w:r').map { |r_node| Containers::TextRun.new(r_node, @document_properties) }
|
42
59
|
end
|
43
60
|
|
44
61
|
# Iterate over each text run within a paragraph
|
45
62
|
def each_text_run
|
46
63
|
text_runs.each { |tr| yield(tr) }
|
47
64
|
end
|
65
|
+
|
66
|
+
def aligned_left?
|
67
|
+
['left', nil].include?(alignment)
|
68
|
+
end
|
69
|
+
|
70
|
+
def aligned_right?
|
71
|
+
alignment == 'right'
|
72
|
+
end
|
73
|
+
|
74
|
+
def aligned_center?
|
75
|
+
alignment == 'center'
|
76
|
+
end
|
77
|
+
|
78
|
+
def font_size
|
79
|
+
size_tag = @node.xpath('w:pPr//w:sz').first
|
80
|
+
size_tag ? size_tag.attributes['val'].value.to_i / 2 : @font_size
|
81
|
+
end
|
48
82
|
|
49
83
|
alias_method :text, :to_s
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Returns the alignment if any, or nil if left
|
88
|
+
def alignment
|
89
|
+
alignment_tag = @node.xpath('.//w:jc').first
|
90
|
+
alignment_tag ? alignment_tag.attributes['val'].value : nil
|
91
|
+
end
|
92
|
+
|
50
93
|
end
|
51
94
|
end
|
52
95
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'docx/containers/table_row'
|
2
|
+
require 'docx/containers/table_column'
|
3
|
+
require 'docx/containers/container'
|
4
|
+
|
5
|
+
module Docx
|
6
|
+
module Elements
|
7
|
+
module Containers
|
8
|
+
class Table
|
9
|
+
include Container
|
10
|
+
include Elements::Element
|
11
|
+
|
12
|
+
def self.tag
|
13
|
+
'tbl'
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(node)
|
17
|
+
@node = node
|
18
|
+
@properties_tag = 'tblGrid'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Array of row
|
22
|
+
def rows
|
23
|
+
@node.xpath('w:tr').map {|r_node| Containers::TableRow.new(r_node) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def row_count
|
27
|
+
@node.xpath('w:tr').count
|
28
|
+
end
|
29
|
+
|
30
|
+
# Array of column
|
31
|
+
def columns
|
32
|
+
columns_containers = []
|
33
|
+
(0..(column_count-1)).each do |i|
|
34
|
+
columns_containers[i] = Containers::TableColumn.new @node.xpath("w:tr//w:tc[#{i+1}]")
|
35
|
+
end
|
36
|
+
columns_containers
|
37
|
+
end
|
38
|
+
|
39
|
+
def column_count
|
40
|
+
@node.xpath('w:tblGrid/w:gridCol').count
|
41
|
+
end
|
42
|
+
|
43
|
+
# Iterate over each row within a table
|
44
|
+
def each_rows
|
45
|
+
rows.each { |r| yield(r) }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'docx/containers/text_run'
|
2
|
+
require 'docx/containers/container'
|
3
|
+
|
4
|
+
module Docx
|
5
|
+
module Elements
|
6
|
+
module Containers
|
7
|
+
class TableCell
|
8
|
+
include Container
|
9
|
+
include Elements::Element
|
10
|
+
|
11
|
+
def self.tag
|
12
|
+
'tc'
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(node)
|
16
|
+
@node = node
|
17
|
+
@properties_tag = 'tcPr'
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return text of paragraph's cell
|
21
|
+
def to_s
|
22
|
+
paragraphs.map(&:text).join('')
|
23
|
+
end
|
24
|
+
|
25
|
+
# Array of paragraphs contained within cell
|
26
|
+
def paragraphs
|
27
|
+
@node.xpath('w:p').map {|p_node| Containers::Paragraph.new(p_node) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Iterate over each text run within a paragraph's cell
|
31
|
+
def each_paragraph
|
32
|
+
paragraphs.each { |tr| yield(tr) }
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :text, :to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'docx/containers/table_cell'
|
2
|
+
require 'docx/containers/container'
|
3
|
+
|
4
|
+
module Docx
|
5
|
+
module Elements
|
6
|
+
module Containers
|
7
|
+
class TableColumn
|
8
|
+
include Container
|
9
|
+
include Elements::Element
|
10
|
+
|
11
|
+
def self.tag
|
12
|
+
'w:gridCol'
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(cell_nodes)
|
16
|
+
@node = ''
|
17
|
+
@properties_tag = ''
|
18
|
+
@cells = cell_nodes.map { |c_node| Containers::TableCell.new(c_node) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Array of cells contained within row
|
22
|
+
def cells
|
23
|
+
@cells
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'docx/containers/table_cell'
|
2
|
+
require 'docx/containers/container'
|
3
|
+
|
4
|
+
module Docx
|
5
|
+
module Elements
|
6
|
+
module Containers
|
7
|
+
class TableRow
|
8
|
+
include Container
|
9
|
+
include Elements::Element
|
10
|
+
|
11
|
+
def self.tag
|
12
|
+
'tr'
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(node)
|
16
|
+
@node = node
|
17
|
+
@properties_tag = ''
|
18
|
+
end
|
19
|
+
|
20
|
+
# Array of cells contained within row
|
21
|
+
def cells
|
22
|
+
@node.xpath('w:tc').map {|c_node| Containers::TableCell.new(c_node) }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -13,17 +13,21 @@ module Docx
|
|
13
13
|
underline: false
|
14
14
|
}
|
15
15
|
|
16
|
-
|
16
|
+
def self.tag
|
17
|
+
'r'
|
18
|
+
end
|
17
19
|
|
18
20
|
attr_reader :text
|
19
21
|
attr_reader :formatting
|
20
22
|
|
21
|
-
def initialize(node)
|
23
|
+
def initialize(node, document_properties = {})
|
22
24
|
@node = node
|
23
25
|
@text_nodes = @node.xpath('w:t').map {|t_node| Elements::Text.new(t_node) }
|
24
26
|
@properties_tag = 'rPr'
|
25
27
|
@text = parse_text || ''
|
26
28
|
@formatting = parse_formatting || DEFAULT_FORMATTING
|
29
|
+
@document_properties = document_properties
|
30
|
+
@font_size = @document_properties[:font_size]
|
27
31
|
end
|
28
32
|
|
29
33
|
# Set text of text run
|
@@ -52,7 +56,20 @@ module Docx
|
|
52
56
|
def to_s
|
53
57
|
@text
|
54
58
|
end
|
55
|
-
|
59
|
+
|
60
|
+
# Return text as a HTML fragment with formatting based on properties.
|
61
|
+
def to_html
|
62
|
+
html = @text
|
63
|
+
html = html_tag(:em, content: html) if italicized?
|
64
|
+
html = html_tag(:strong, content: html) if bolded?
|
65
|
+
styles = {}
|
66
|
+
styles['text-decoration'] = 'underline' if underlined?
|
67
|
+
# No need to be granular with font size down to the span level if it doesn't vary.
|
68
|
+
styles['font-size'] = "#{font_size}pt" if font_size != @font_size
|
69
|
+
html = html_tag(:span, content: html, styles: styles) unless styles.empty?
|
70
|
+
return html
|
71
|
+
end
|
72
|
+
|
56
73
|
def italicized?
|
57
74
|
@formatting[:italic]
|
58
75
|
end
|
@@ -64,6 +81,11 @@ module Docx
|
|
64
81
|
def underlined?
|
65
82
|
@formatting[:underline]
|
66
83
|
end
|
84
|
+
|
85
|
+
def font_size
|
86
|
+
size_tag = @node.xpath('w:rPr//w:sz').first
|
87
|
+
size_tag ? size_tag.attributes['val'].value.to_i / 2 : @font_size
|
88
|
+
end
|
67
89
|
end
|
68
90
|
end
|
69
91
|
end
|
data/lib/docx/document.rb
CHANGED
@@ -1,32 +1,47 @@
|
|
1
|
-
require 'docx/
|
2
|
-
require '
|
1
|
+
require 'docx/containers'
|
2
|
+
require 'docx/elements'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'zip'
|
3
5
|
|
4
6
|
module Docx
|
5
7
|
# The Document class wraps around a docx file and provides methods to
|
6
8
|
# interface with it.
|
7
|
-
#
|
9
|
+
#
|
8
10
|
# # get a Docx::Document for a docx file in the local directory
|
9
11
|
# doc = Docx::Document.open("test.docx")
|
10
|
-
#
|
12
|
+
#
|
11
13
|
# # get the text from the document
|
12
14
|
# puts doc.text
|
13
|
-
#
|
15
|
+
#
|
14
16
|
# # do the same thing in a block
|
15
17
|
# Docx::Document.open("test.docx") do |d|
|
16
18
|
# puts d.text
|
17
19
|
# end
|
18
20
|
class Document
|
19
|
-
|
20
|
-
|
21
|
+
attr_reader :xml, :doc, :zip, :styles
|
22
|
+
|
21
23
|
def initialize(path, &block)
|
22
24
|
@replace = {}
|
25
|
+
@zip = Zip::File.open(path)
|
26
|
+
@document_xml = @zip.read('word/document.xml')
|
27
|
+
@doc = Nokogiri::XML(@document_xml)
|
28
|
+
@styles_xml = @zip.read('word/styles.xml')
|
29
|
+
@styles = Nokogiri::XML(@styles_xml)
|
23
30
|
if block_given?
|
24
|
-
|
25
|
-
|
26
|
-
@parser = Parser.new(File.expand_path(path))
|
31
|
+
yield self
|
32
|
+
@zip.close
|
27
33
|
end
|
28
34
|
end
|
29
|
-
|
35
|
+
|
36
|
+
|
37
|
+
# This stores the current global document properties, for now
|
38
|
+
def document_properties
|
39
|
+
{
|
40
|
+
font_size: font_size
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
|
30
45
|
# With no associated block, Docx::Document.open is a synonym for Docx::Document.new. If the optional code block is given, it will be passed the opened +docx+ file as an argument and the Docx::Document oject will automatically be closed when the block terminates. The values of the block will be returned from Docx::Document.open.
|
31
46
|
# call-seq:
|
32
47
|
# open(filepath) => file
|
@@ -35,28 +50,57 @@ module Docx
|
|
35
50
|
self.new(path, &block)
|
36
51
|
end
|
37
52
|
|
53
|
+
def paragraphs
|
54
|
+
@doc.xpath('//w:document//w:body//w:p').map { |p_node| parse_paragraph_from p_node }
|
55
|
+
end
|
56
|
+
|
57
|
+
def bookmarks
|
58
|
+
bkmrks_hsh = Hash.new
|
59
|
+
bkmrks_ary = @doc.xpath('//w:bookmarkStart').map { |b_node| parse_bookmark_from b_node }
|
60
|
+
# auto-generated by office 2010
|
61
|
+
bkmrks_ary.reject! {|b| b.name == "_GoBack" }
|
62
|
+
bkmrks_ary.each {|b| bkmrks_hsh[b.name] = b }
|
63
|
+
bkmrks_hsh
|
64
|
+
end
|
65
|
+
|
66
|
+
def tables
|
67
|
+
@doc.xpath('//w:document//w:body//w:tbl').map { |t_node| parse_table_from t_node }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Some documents have this set, others don't.
|
71
|
+
# Values are returned as half-points, so to get points, that's why it's divided by 2.
|
72
|
+
def font_size
|
73
|
+
size_tag = @styles.xpath('//w:docDefaults//w:rPrDefault//w:rPr//w:sz').first
|
74
|
+
size_tag ? size_tag.attributes['val'].value.to_i / 2 : nil
|
75
|
+
end
|
76
|
+
|
38
77
|
##
|
39
78
|
# *Deprecated*
|
40
|
-
#
|
79
|
+
#
|
41
80
|
# Iterates over paragraphs within document
|
42
81
|
# call-seq:
|
43
82
|
# each_paragraph => Enumerator
|
44
83
|
def each_paragraph
|
45
84
|
paragraphs.each { |p| yield(p) }
|
46
85
|
end
|
47
|
-
|
86
|
+
|
48
87
|
# call-seq:
|
49
88
|
# to_s -> string
|
50
89
|
def to_s
|
51
90
|
paragraphs.map(&:to_s).join("\n")
|
52
91
|
end
|
53
92
|
|
93
|
+
# Output entire document as a String HTML fragment
|
94
|
+
def to_html
|
95
|
+
paragraphs.map(&:to_html).join('\n')
|
96
|
+
end
|
97
|
+
|
54
98
|
# Save document to provided path
|
55
99
|
# call-seq:
|
56
100
|
# save(filepath) => void
|
57
101
|
def save(path)
|
58
102
|
update
|
59
|
-
Zip::
|
103
|
+
Zip::OutputStream.open(path) do |out|
|
60
104
|
zip.each do |entry|
|
61
105
|
out.put_next_entry(entry.name)
|
62
106
|
|
@@ -69,19 +113,36 @@ module Docx
|
|
69
113
|
end
|
70
114
|
zip.close
|
71
115
|
end
|
72
|
-
|
116
|
+
|
73
117
|
alias_method :text, :to_s
|
74
118
|
|
119
|
+
def replace_entry(entry_path, file_contents)
|
120
|
+
@replace[entry_path] = file_contents
|
121
|
+
end
|
122
|
+
|
75
123
|
private
|
76
124
|
|
77
125
|
#--
|
78
126
|
# TODO: Flesh this out to be compatible with other files
|
79
|
-
# TODO: Method to set flag on files that have been edited, probably by inserting something at the
|
127
|
+
# TODO: Method to set flag on files that have been edited, probably by inserting something at the
|
80
128
|
# end of methods that make edits?
|
81
129
|
#++
|
82
130
|
def update
|
83
|
-
|
131
|
+
replace_entry "word/document.xml", doc.serialize(:save_with => 0)
|
132
|
+
end
|
133
|
+
|
134
|
+
# generate Elements::Containers::Paragraph from paragraph XML node
|
135
|
+
def parse_paragraph_from(p_node)
|
136
|
+
Elements::Containers::Paragraph.new(p_node, document_properties)
|
84
137
|
end
|
85
138
|
|
139
|
+
# generate Elements::Bookmark from bookmark XML node
|
140
|
+
def parse_bookmark_from(b_node)
|
141
|
+
Elements::Bookmark.new(b_node)
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_table_from(t_node)
|
145
|
+
Elements::Containers::Table.new(t_node)
|
146
|
+
end
|
86
147
|
end
|
87
148
|
end
|
@@ -55,10 +55,34 @@ module Docx
|
|
55
55
|
self.class.new(@node.dup)
|
56
56
|
end
|
57
57
|
|
58
|
+
# A method to wrap content in an HTML tag.
|
59
|
+
# Currently used in paragraph and text_run for the to_html methods
|
60
|
+
#
|
61
|
+
# content:: The base text content for the tag.
|
62
|
+
# styles:: Hash of the inline CSS styles to be applied. e.g.
|
63
|
+
# { 'font-size' => '12pt', 'text-decoration' => 'underline' }
|
64
|
+
#
|
65
|
+
def html_tag(name, options = {})
|
66
|
+
content = options[:content]
|
67
|
+
styles = options[:styles]
|
68
|
+
|
69
|
+
html = "<#{name.to_s}"
|
70
|
+
unless styles.nil? || styles.empty?
|
71
|
+
styles_array = []
|
72
|
+
styles.each do |property, value|
|
73
|
+
styles_array << "#{property.to_s}:#{value};"
|
74
|
+
end
|
75
|
+
html << " style=\"#{styles_array.join('')}\""
|
76
|
+
end
|
77
|
+
html << ">"
|
78
|
+
html << content if content
|
79
|
+
html << "</#{name.to_s}>"
|
80
|
+
end
|
81
|
+
|
58
82
|
module ClassMethods
|
59
83
|
def create_with(element)
|
60
84
|
# Need to somehow get the xml document accessible here by default, but this is alright in the interim
|
61
|
-
self.new(Nokogiri::XML::Node.new("w:#{self.
|
85
|
+
self.new(Nokogiri::XML::Node.new("w:#{self.tag}", element.node))
|
62
86
|
end
|
63
87
|
|
64
88
|
def create_within(element)
|
data/lib/docx/elements/text.rb
CHANGED
data/lib/docx/version.rb
CHANGED
metadata
CHANGED
@@ -1,48 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.07
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Christopher Hunt
|
8
9
|
- Marcus Ortiz
|
10
|
+
- Higgins Dragon
|
11
|
+
- Toms Mikoss
|
12
|
+
- Sebastian Wittenkamp
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
|
-
cert_chain:
|
12
|
-
-
|
13
|
-
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURjRENDQWxpZ0F3SUJB
|
14
|
-
Z0lCQVRBTkJna3Foa2lHOXcwQkFRVUZBREEvTVJFd0R3WURWUVFEREFoamFI
|
15
|
-
SmgKYUhWdWRERVZNQk1HQ2dtU0pvbVQ4aXhrQVJrV0JXZHRZV2xzTVJNd0VR
|
16
|
-
WUtDWkltaVpQeUxHUUJHUllEWTI5dApNQjRYRFRFek1EUXhOVEl3TURFeU4x
|
17
|
-
b1hEVEUwTURReE5USXdNREV5TjFvd1B6RVJNQThHQTFVRUF3d0lZMmh5CllX
|
18
|
-
aDFiblF4RlRBVEJnb0praWFKay9Jc1pBRVpGZ1ZuYldGcGJERVRNQkVHQ2dt
|
19
|
-
U0pvbVQ4aXhrQVJrV0EyTnYKYlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFB
|
20
|
-
RGdnRVBBRENDQVFvQ2dnRUJBTFhycTdlWHRQaTYrUDJuZ3BYOQpSbmdXWUJz
|
21
|
-
alhMZ0dhTnIxbDBieFBVUGpJN3pxaVF2N3JWOGkvNUdzNVZ4MFZSbTVtMU14
|
22
|
-
OHNtK1c3akl0MExrClJVVGlvcG9TMHdlRUdJekRDZzc4Ukp4TEhBZ1g0Z2NU
|
23
|
-
Vis2dGZvTzV2Qzc5WGJ5VFpZVExRbXFrWWYwSDE1RnYKVmRPd2dJS3hPaW42
|
24
|
-
bThWSGdUdFhWcjhzeGxNRDlsN1Uzb3M3YmNrSDV3Lzk1SGcrNzI2NkRKdHl2
|
25
|
-
eEpPUG5RLwpuOUJwblBhMEN0bXlacEY3WStmdWMzRE1LVUprY2hRdmx2OE5o
|
26
|
-
cWpmNTF4T2hTQ1hVTXpFbHJlMVZvNXBON2VaClFsNERsaTFJeGNZY0R1NVpQ
|
27
|
-
ck4rcEVMelYvS3QrV0JZaW1Sa3Era0ZxOGhYSzY1ODZGNGM3ZmMrSStTUkc4
|
28
|
-
L2YKWTJVQ0F3RUFBYU4zTUhVd0NRWURWUjBUQkFJd0FEQUxCZ05WSFE4RUJB
|
29
|
-
TUNCTEF3SFFZRFZSME9CQllFRkVlNQorZmRySFZCb1F6cnlWNEVYMmdiTGVQ
|
30
|
-
clVNQjBHQTFVZEVRUVdNQlNCRW1Ob2NtRm9kVzUwUUdkdFlXbHNMbU52CmJU
|
31
|
-
QWRCZ05WSFJJRUZqQVVnUkpqYUhKaGFIVnVkRUJuYldGcGJDNWpiMjB3RFFZ
|
32
|
-
SktvWklodmNOQVFFRkJRQUQKZ2dFQkFMSzl1V25oMWliTUZzT2c3WGlKWWdV
|
33
|
-
dlVoNUt4aWxhTHdMSHRHTDFHd3U2ZlRBMU9DSU5CeDJiMUxMbgpRNTdYQWhv
|
34
|
-
dkxlOGN3Qko0RnV6RXV1aUpMTlhlOU5FTDU2L1ZpbjloMTFlVktpOHA2YTEv
|
35
|
-
MC9XeTlsWEVVSHFBCkFUR0JMTHM0MXFXN2JuV3dSK09TZ2dySitJQkYzTGYr
|
36
|
-
VjNzSHhiNkxHV0h4ekNNMHpIdU5OWEJsQTdnRWQyNFAKQ0llcEtTdnlwQUdP
|
37
|
-
ckhRbGdpOTNPbkxEWjdKa3pCMk1wcDA0em5NSllQOGZIdGJCTkE2bFUxL2tK
|
38
|
-
NEV0UFhmRQpLdFE1SGpuNFVDNTg0R0pyR01haFVnbXhMbmZleXVZWXVZTlFF
|
39
|
-
M1VzVlVQYXl6eGtQVW9DOFZzT0orV1ZmMnMrCkcxL1VkNGRVYkVtOGdRL2J4
|
40
|
-
bDM1TzBBdkhCcz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
41
|
-
date: 2013-06-08 00:00:00.000000000 Z
|
15
|
+
cert_chain: []
|
16
|
+
date: 2014-10-29 00:00:00.000000000 Z
|
42
17
|
dependencies:
|
43
18
|
- !ruby/object:Gem::Dependency
|
44
19
|
name: nokogiri
|
45
20
|
requirement: !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
46
22
|
requirements:
|
47
23
|
- - ~>
|
48
24
|
- !ruby/object:Gem::Version
|
@@ -50,6 +26,7 @@ dependencies:
|
|
50
26
|
type: :runtime
|
51
27
|
prerelease: false
|
52
28
|
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
53
30
|
requirements:
|
54
31
|
- - ~>
|
55
32
|
- !ruby/object:Gem::Version
|
@@ -57,17 +34,35 @@ dependencies:
|
|
57
34
|
- !ruby/object:Gem::Dependency
|
58
35
|
name: rubyzip
|
59
36
|
requirement: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
60
38
|
requirements:
|
61
39
|
- - ~>
|
62
40
|
- !ruby/object:Gem::Version
|
63
|
-
version:
|
41
|
+
version: 1.1.6
|
64
42
|
type: :runtime
|
65
43
|
prerelease: false
|
66
44
|
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
67
46
|
requirements:
|
68
47
|
- - ~>
|
69
48
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
49
|
+
version: 1.1.6
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rspec
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
type: :development
|
59
|
+
prerelease: false
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
71
66
|
description: a ruby library/gem for interacting with .docx files
|
72
67
|
email:
|
73
68
|
- chrahunt@gmail.com
|
@@ -79,6 +74,10 @@ files:
|
|
79
74
|
- LICENSE.md
|
80
75
|
- lib/docx/containers/container.rb
|
81
76
|
- lib/docx/containers/paragraph.rb
|
77
|
+
- lib/docx/containers/table.rb
|
78
|
+
- lib/docx/containers/table_cell.rb
|
79
|
+
- lib/docx/containers/table_column.rb
|
80
|
+
- lib/docx/containers/table_row.rb
|
82
81
|
- lib/docx/containers/text_run.rb
|
83
82
|
- lib/docx/containers.rb
|
84
83
|
- lib/docx/core_ext/module.rb
|
@@ -87,31 +86,31 @@ files:
|
|
87
86
|
- lib/docx/elements/element.rb
|
88
87
|
- lib/docx/elements/text.rb
|
89
88
|
- lib/docx/elements.rb
|
90
|
-
- lib/docx/parser.rb
|
91
89
|
- lib/docx/version.rb
|
92
90
|
- lib/docx.rb
|
93
91
|
homepage: https://github.com/chrahunt/docx
|
94
92
|
licenses: []
|
95
|
-
metadata: {}
|
96
93
|
post_install_message:
|
97
94
|
rdoc_options: []
|
98
95
|
require_paths:
|
99
96
|
- lib
|
100
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
101
99
|
requirements:
|
102
100
|
- - ! '>='
|
103
101
|
- !ruby/object:Gem::Version
|
104
102
|
version: '0'
|
105
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
106
105
|
requirements:
|
107
106
|
- - ! '>='
|
108
107
|
- !ruby/object:Gem::Version
|
109
108
|
version: '0'
|
110
109
|
requirements: []
|
111
110
|
rubyforge_project:
|
112
|
-
rubygems_version:
|
111
|
+
rubygems_version: 1.8.28
|
113
112
|
signing_key:
|
114
|
-
specification_version:
|
113
|
+
specification_version: 3
|
115
114
|
summary: a ruby library/gem for interacting with .docx files
|
116
115
|
test_files: []
|
117
116
|
has_rdoc:
|
checksums.yaml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
---
|
2
|
-
!binary "U0hBMQ==":
|
3
|
-
metadata.gz: !binary |-
|
4
|
-
YzIyMTI3NGE3YWNhMjYyMjUzMTZjYWZjMmJkYjU0OGI4ZDg2OTM3MQ==
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZmJjNWZjMzc2OTM4NDFmMTkwNzI2Y2JhM2IwZDE5Mzc0MjY3M2I1Mw==
|
7
|
-
!binary "U0hBNTEy":
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MmIyZWM4MDJjMjY3NGYzZDUzNjBiYmE2YjllZmNiZTA4NjkyYzE3ODg3ZmFi
|
10
|
-
OTA4YTQ5ZTY2MzA4Mjc5YWI0YjIyYmIyNzFjZjk3ZWZmODQxNWUwMTNlZjNl
|
11
|
-
N2ZiOTUxYzg5ZmYzNzc5MmI3ZjlhZTNiMDY0ZjNmYTE5NzVjOWE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MTRhMjAxMmJlODRhOTJhMzM4OGExZGI5NGFiZTdmZDczZmI0N2QyYjQ0ZDhk
|
14
|
-
OGQ0MjlkYWEyNWJlMzhmMGY2ZTFlODVjYmY5MThjM2Q1NzdiOTRkYzlhYjdk
|
15
|
-
OWIxNGJkOWM5MzkzNTFlNzNkN2VkOWEzNmRjOWJhOTMxZWY1OTA=
|
checksums.yaml.gz.sig
DELETED
Binary file
|
data.tar.gz.sig
DELETED
Binary file
|
data/lib/docx/parser.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'docx/containers'
|
2
|
-
require 'docx/elements'
|
3
|
-
require 'nokogiri'
|
4
|
-
require 'zip/zip'
|
5
|
-
|
6
|
-
module Docx
|
7
|
-
class Parser
|
8
|
-
attr_reader :xml, :doc, :zip
|
9
|
-
|
10
|
-
def initialize(path)
|
11
|
-
@zip = Zip::ZipFile.open(path)
|
12
|
-
@xml = @zip.read('word/document.xml')
|
13
|
-
@doc = Nokogiri::XML(@xml)
|
14
|
-
if block_given?
|
15
|
-
yield self
|
16
|
-
@zip.close
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def paragraphs
|
21
|
-
@doc.xpath('//w:document//w:body//w:p').map { |p_node| parse_paragraph_from p_node }
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns hash of bookmarks
|
25
|
-
def bookmarks
|
26
|
-
bkmrks_hsh = Hash.new
|
27
|
-
bkmrks_ary = @doc.xpath('//w:bookmarkStart').map { |b_node| parse_bookmark_from b_node }
|
28
|
-
# auto-generated by office 2010
|
29
|
-
bkmrks_ary.reject! {|b| b.name == "_GoBack" }
|
30
|
-
bkmrks_ary.each {|b| bkmrks_hsh[b.name] = b }
|
31
|
-
bkmrks_hsh
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
# generate Elements::Containers::Paragraph from paragraph XML node
|
37
|
-
def parse_paragraph_from(p_node)
|
38
|
-
Elements::Containers::Paragraph.new(p_node)
|
39
|
-
end
|
40
|
-
|
41
|
-
# generate Elements::Bookmark from bookmark XML node
|
42
|
-
def parse_bookmark_from(b_node)
|
43
|
-
Elements::Bookmark.new(b_node)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
metadata.gz.sig
DELETED