docx 0.2.03 → 0.2.07
Sign up to get free protection for your applications and to get access to all the features.
- 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