parent
513faa67c1
commit
93b21cee78
|
@ -12,3 +12,5 @@ vrt/report.html
|
|||
reg.json
|
||||
docx-core/tests/output/*.docx
|
||||
docx-wasm/*.tgz
|
||||
|
||||
docx-core/tests/output/*.json
|
|
@ -13,6 +13,16 @@ dependencies = [
|
|||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.40"
|
||||
|
@ -48,6 +58,31 @@ name = "cfg-if"
|
|||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clicolors-control"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.6"
|
||||
|
@ -83,6 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "docx-rs"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"insta 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -101,6 +137,16 @@ dependencies = [
|
|||
"wasm-bindgen-test 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.6"
|
||||
|
@ -145,6 +191,27 @@ dependencies = [
|
|||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
|
@ -168,6 +235,11 @@ name = "libc"
|
|||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
|
@ -254,6 +326,19 @@ dependencies = [
|
|||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
|
@ -297,6 +382,17 @@ dependencies = [
|
|||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sourcefile"
|
||||
version = "0.1.4"
|
||||
|
@ -323,6 +419,14 @@ dependencies = [
|
|||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termios"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.5"
|
||||
|
@ -504,6 +608,14 @@ name = "xml-rs"
|
|||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.4"
|
||||
|
@ -517,24 +629,32 @@ dependencies = [
|
|||
[metadata]
|
||||
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
|
||||
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
|
||||
"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
|
||||
"checksum console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0"
|
||||
"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
|
||||
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
|
||||
"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
|
||||
"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
|
||||
"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f"
|
||||
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum insta 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8df742abee84dbf27d20869c9adf77b0d8f7ea3eead13c2c9e3998d136a97058"
|
||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
"checksum js-sys 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "a60f6ca5eb7ae3014e3ab34e3189a1560267245216e19f76a021a4c669817e62"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||
"checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
|
||||
|
@ -546,15 +666,19 @@ dependencies = [
|
|||
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
|
||||
"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "eab8f15f15d6c41a154c1b128a22f2dfabe350ef53c40953d84e36155c91192b"
|
||||
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
|
||||
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
|
||||
"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c"
|
||||
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
|
||||
"checksum thiserror 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f9fb62ff737e573b1e677459bea6fd023cd5d6e868c3242d3cdf3ef2f0554824"
|
||||
"checksum thiserror-impl 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24069c0ba08aab54289d6a25f5036d94afc61e1538bbc42ae5501df141c9027d"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
@ -576,4 +700,5 @@ dependencies = [
|
|||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
||||
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
||||
"checksum zip 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e41ff37ba788e2169b19fa70253b70cb53d9f2db9fb9aea9bcfc5047e02c3bae"
|
||||
|
|
|
@ -29,3 +29,4 @@ serde_json = "1.0"
|
|||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
insta = "0.13"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Read;
|
||||
use xml::reader::{EventReader, XmlEvent};
|
||||
|
||||
|
@ -9,7 +9,7 @@ use crate::xml_builder::*;
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct ContentTypes {
|
||||
types: HashMap<String, String>,
|
||||
types: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl ContentTypes {
|
||||
|
@ -75,7 +75,7 @@ impl ContentTypes {
|
|||
impl Default for ContentTypes {
|
||||
fn default() -> Self {
|
||||
ContentTypes {
|
||||
types: HashMap::new(),
|
||||
types: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ mod tests {
|
|||
let xml = r#"<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"></Override></Types>"#;
|
||||
let c = ContentTypes::from_xml(xml.as_bytes()).unwrap();
|
||||
let mut types = HashMap::new();
|
||||
let mut types = BTreeMap::new();
|
||||
types.insert(
|
||||
"/word/document.xml".to_owned(),
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
||||
|
|
|
@ -12,6 +12,7 @@ pub struct Level {
|
|||
pub format: NumberFormat,
|
||||
pub text: LevelText,
|
||||
pub jc: LevelJc,
|
||||
pub pstyle: Option<String>,
|
||||
pub paragraph_property: ParagraphProperty,
|
||||
}
|
||||
|
||||
|
@ -29,6 +30,7 @@ impl Level {
|
|||
format,
|
||||
text,
|
||||
jc,
|
||||
pstyle: None,
|
||||
paragraph_property: ParagraphProperty::new(),
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +44,11 @@ impl Level {
|
|||
self.paragraph_property = self.paragraph_property.indent(left, special_indent, end);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn paragraph_style(mut self, style_id: impl Into<String>) -> Self {
|
||||
self.pstyle = Some(style_id.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Level {
|
||||
|
|
|
@ -14,6 +14,12 @@ impl Start {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Start {
|
||||
fn default() -> Self {
|
||||
Start { val: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Start {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
|
|
|
@ -102,6 +102,11 @@ impl Docx {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn numberings(mut self, n: Numberings) -> Self {
|
||||
self.numberings = n;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
|
||||
if p.has_numbering {
|
||||
// If this document has numbering, set numberings.xml to document_rels.
|
||||
|
@ -160,7 +165,7 @@ impl Docx {
|
|||
|
||||
pub fn json(&mut self) -> String {
|
||||
self.update_comments();
|
||||
serde_json::to_string(&self).unwrap()
|
||||
serde_json::to_string_pretty(&self).unwrap()
|
||||
}
|
||||
|
||||
// Traverse and clone comments from document and add to comments node.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use xml::attribute::OwnedAttribute;
|
||||
|
||||
use super::super::errors::*;
|
||||
|
||||
pub fn read_indent_level(attrs: &[OwnedAttribute]) -> Result<usize, ReaderError> {
|
||||
let mut l = 0;
|
||||
for a in attrs {
|
||||
let local_name = &a.name.local_name;
|
||||
if local_name == "ilvl" {
|
||||
l = usize::from_str(&a.value)?;
|
||||
}
|
||||
}
|
||||
Ok(l)
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
mod indent;
|
||||
mod indent_level;
|
||||
mod width;
|
||||
|
||||
pub use indent::*;
|
||||
pub use indent_level::*;
|
||||
pub use width::*;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{Cursor, Read};
|
||||
use std::path::*;
|
||||
use std::str::FromStr;
|
||||
|
@ -10,7 +10,7 @@ use super::*;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ReadDocumentRels {
|
||||
rels: HashMap<String, PathBuf>,
|
||||
rels: BTreeMap<String, PathBuf>,
|
||||
}
|
||||
|
||||
impl ReadDocumentRels {
|
||||
|
@ -40,7 +40,7 @@ fn read_rels_xml<R: Read>(
|
|||
) -> Result<ReadDocumentRels, ReaderError> {
|
||||
let mut parser = EventReader::new(reader);
|
||||
let mut rels = ReadDocumentRels {
|
||||
rels: HashMap::new(),
|
||||
rels: BTreeMap::new(),
|
||||
};
|
||||
loop {
|
||||
let e = parser.next();
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::reader::{EventReader, XmlEvent};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl ElementReader for Level {
|
||||
fn read<R: Read>(
|
||||
r: &mut EventReader<R>,
|
||||
attrs: &[OwnedAttribute],
|
||||
) -> Result<Self, ReaderError> {
|
||||
let level = read_indent_level(attrs)?;
|
||||
let mut style_id = None;
|
||||
let mut start = Start::default();
|
||||
let mut num_fmt = NumberFormat::new("decimal");
|
||||
let mut level_text = LevelText::new("");
|
||||
let mut jc = LevelJc::new("left");
|
||||
|
||||
let mut indent_start = 0;
|
||||
let mut special_indent = None;
|
||||
let mut indent_end = None;
|
||||
let mut has_indent = false;
|
||||
|
||||
loop {
|
||||
let e = r.next();
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
attributes, name, ..
|
||||
}) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
match e {
|
||||
XMLElement::ParagraphStyle => {
|
||||
let id = attributes[0].value.clone();
|
||||
style_id = Some(id);
|
||||
}
|
||||
XMLElement::Start => {
|
||||
start = Start::new(usize::from_str(&attributes[0].value)?);
|
||||
}
|
||||
XMLElement::NumberFormat => {
|
||||
num_fmt = NumberFormat::new(attributes[0].value.clone());
|
||||
}
|
||||
XMLElement::LevelText => {
|
||||
level_text = LevelText::new(attributes[0].value.clone());
|
||||
}
|
||||
XMLElement::LevelJustification => {
|
||||
jc = LevelJc::new(attributes[0].value.clone());
|
||||
}
|
||||
XMLElement::Indent => {
|
||||
let i = read_indent(&attributes)?;
|
||||
indent_start = i.0;
|
||||
indent_end = i.1;
|
||||
special_indent = i.2;
|
||||
has_indent = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::Level = e {
|
||||
let mut l = Level::new(level, start, num_fmt, level_text, jc);
|
||||
if let Some(style_id) = style_id {
|
||||
l = l.paragraph_style(style_id);
|
||||
}
|
||||
if has_indent {
|
||||
l = l.indent(indent_start, special_indent, indent_end);
|
||||
}
|
||||
return Ok(l);
|
||||
}
|
||||
}
|
||||
Err(_) => return Err(ReaderError::XMLReadError),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,9 @@ mod document_rels;
|
|||
mod errors;
|
||||
mod from_xml;
|
||||
mod insert;
|
||||
mod level;
|
||||
mod numbering_property;
|
||||
mod numberings;
|
||||
mod paragraph;
|
||||
mod rels;
|
||||
mod run;
|
||||
|
@ -31,6 +33,8 @@ const DOC_RELATIONSHIP_TYPE: &str =
|
|||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
||||
const STYLE_RELATIONSHIP_TYPE: &str =
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||
const NUMBERING_RELATIONSHIP_TYPE: &str =
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
|
||||
|
||||
pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
||||
let cur = Cursor::new(buf);
|
||||
|
@ -53,12 +57,24 @@ pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
|||
|
||||
// Read document relationships
|
||||
let rels = read_document_rels(&mut archive, &main_rel.2)?;
|
||||
|
||||
// Read styles
|
||||
let style_path = rels
|
||||
.find_target_path(STYLE_RELATIONSHIP_TYPE)
|
||||
.ok_or(ReaderError::DocumentStylesNotFoundError)?;
|
||||
let styles_xml = archive.by_name(style_path.to_str().expect("should have styles"))?;
|
||||
let styles = Styles::from_xml(styles_xml)?;
|
||||
|
||||
let docx = Docx::new().document(document).styles(styles);
|
||||
// Read numberings
|
||||
let num_path = rels
|
||||
.find_target_path(NUMBERING_RELATIONSHIP_TYPE)
|
||||
.ok_or(ReaderError::DocumentStylesNotFoundError)?;
|
||||
let num_xml = archive.by_name(num_path.to_str().expect("should have numberings"))?;
|
||||
let nums = Numberings::from_xml(num_xml)?;
|
||||
|
||||
let docx = Docx::new()
|
||||
.document(document)
|
||||
.styles(styles)
|
||||
.numberings(nums);
|
||||
Ok(docx)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
use std::io::Read;
|
||||
use xml::reader::{EventReader, XmlEvent};
|
||||
|
||||
use super::*;
|
||||
use crate::reader::{FromXML, ReaderError};
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
impl FromXML for Numberings {
|
||||
fn from_xml<R: Read>(reader: R) -> Result<Self, ReaderError> {
|
||||
let mut parser = EventReader::new(reader);
|
||||
let mut nums = Self::default();
|
||||
loop {
|
||||
let e = parser.next();
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
attributes, name, ..
|
||||
}) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
match e {
|
||||
XMLElement::AbstractNumbering => {
|
||||
let mut id = 0;
|
||||
for a in attributes {
|
||||
let local_name = &a.name.local_name;
|
||||
if local_name == "abstractNumId" {
|
||||
id = usize::from_str(&a.value)?;
|
||||
}
|
||||
}
|
||||
let mut abs_num = AbstractNumbering::new(id);
|
||||
loop {
|
||||
let e = parser.next();
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
attributes, name, ..
|
||||
}) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::Level = e {
|
||||
let l = Level::read(&mut parser, &attributes)?;
|
||||
abs_num = abs_num.add_level(l);
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::AbstractNumbering = e {
|
||||
nums = nums.add_abstract_numbering(abs_num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
XMLElement::Num => {
|
||||
let mut id = 0;
|
||||
for a in attributes {
|
||||
let local_name = &a.name.local_name;
|
||||
if local_name == "numId" {
|
||||
id = usize::from_str(&a.value)?;
|
||||
}
|
||||
}
|
||||
let mut abs_num_id = 0;
|
||||
loop {
|
||||
let e = parser.next();
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
attributes, name, ..
|
||||
}) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::AbstractNumberingId = e {
|
||||
abs_num_id = usize::from_str(&attributes[0].value)?;
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::Num = e {
|
||||
nums =
|
||||
nums.add_numbering(Numbering::new(id, abs_num_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||
if let XMLElement::Numbering = e {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndDocument { .. }) => break,
|
||||
Err(_) => return Err(ReaderError::XMLReadError),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(nums)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::types::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_numberings_from_xml() {
|
||||
let xml =
|
||||
r#"<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
|
||||
<w:abstractNum w:abstractNumId="0" w15:restartNumberingAfterBreak="0">
|
||||
<w:multiLevelType w:val="hybridMultilevel"></w:multiLevelType>
|
||||
<w:lvl w:ilvl="0" w15:tentative="1">
|
||||
<w:start w:val="1"></w:start>
|
||||
<w:numFmt w:val="bullet"></w:numFmt>
|
||||
<w:lvlText w:val="●"></w:lvlText>
|
||||
<w:lvlJc w:val="left"></w:lvlJc>
|
||||
<w:pPr>
|
||||
<w:ind w:left="720" w:hanging="360"></w:ind>
|
||||
</w:pPr>
|
||||
<w:rPr></w:rPr>
|
||||
</w:lvl>
|
||||
</w:abstractNum>
|
||||
<w:num w:numId="1">
|
||||
<w:abstractNumId w:val="0"></w:abstractNumId>
|
||||
</w:num>
|
||||
</w:numbering>"#;
|
||||
let n = Numberings::from_xml(xml.as_bytes()).unwrap();
|
||||
let mut nums = Numberings::new();
|
||||
nums = nums
|
||||
.add_abstract_numbering(
|
||||
AbstractNumbering::new(0).add_level(
|
||||
Level::new(
|
||||
0,
|
||||
Start::new(1),
|
||||
NumberFormat::new("bullet"),
|
||||
LevelText::new("●"),
|
||||
LevelJc::new("left"),
|
||||
)
|
||||
.indent(720, Some(SpecialIndentType::Hanging(360)), None),
|
||||
),
|
||||
)
|
||||
.add_numbering(Numbering::new(1, 0));
|
||||
assert_eq!(n, nums)
|
||||
}
|
||||
}
|
|
@ -67,6 +67,15 @@ pub enum XMLElement {
|
|||
Styles,
|
||||
Relationship,
|
||||
Relationships,
|
||||
AbstractNumbering,
|
||||
AbstractNumberingId,
|
||||
Level,
|
||||
Numbering,
|
||||
Num,
|
||||
Start,
|
||||
NumberFormat,
|
||||
LevelText,
|
||||
LevelJustification,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
|
@ -133,6 +142,15 @@ impl FromStr for XMLElement {
|
|||
"styles" => Ok(XMLElement::Styles),
|
||||
"Relationships" => Ok(XMLElement::Relationships),
|
||||
"Relationship" => Ok(XMLElement::Relationship),
|
||||
"abstractNum" => Ok(XMLElement::AbstractNumbering),
|
||||
"abstractNumId" => Ok(XMLElement::AbstractNumberingId),
|
||||
"lvl" => Ok(XMLElement::Level),
|
||||
"numbering" => Ok(XMLElement::Numbering),
|
||||
"num" => Ok(XMLElement::Num),
|
||||
"start" => Ok(XMLElement::Start),
|
||||
"numFmt" => Ok(XMLElement::NumberFormat),
|
||||
"lvlText" => Ok(XMLElement::LevelText),
|
||||
"lvlJc" => Ok(XMLElement::LevelJustification),
|
||||
_ => Ok(XMLElement::Unsupported),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
extern crate docx_rs;
|
||||
|
||||
mod reader;
|
||||
|
||||
use docx_rs::*;
|
||||
|
||||
pub const DUMMY: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
use insta::assert_debug_snapshot;
|
||||
|
||||
use docx_rs::*;
|
||||
use std::fs::*;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
#[test]
|
||||
pub fn read_hello() {
|
||||
let mut file = File::open("../fixtures/hello_world/hello_world.docx").unwrap();
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
let json = read_docx(&buf).unwrap().json();
|
||||
|
||||
assert_debug_snapshot!(&json);
|
||||
|
||||
let path = std::path::Path::new("./tests/output/hello.json");
|
||||
let mut file = std::fs::File::create(&path).unwrap();
|
||||
file.write_all(json.as_bytes()).unwrap();
|
||||
file.flush().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn read_numbering() {
|
||||
let mut file = File::open("../fixtures/numbering/numbering.docx").unwrap();
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
let json = read_docx(&buf).unwrap().json();
|
||||
|
||||
assert_debug_snapshot!(&json);
|
||||
|
||||
let path = std::path::Path::new("./tests/output/numbering.json");
|
||||
let mut file = std::fs::File::create(&path).unwrap();
|
||||
file.write_all(json.as_bytes()).unwrap();
|
||||
file.flush().unwrap();
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue