parent
9eec10e374
commit
d2c1417c98
|
@ -5,7 +5,7 @@ use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||||
pub struct BookmarkEnd {
|
pub struct BookmarkEnd {
|
||||||
id: usize,
|
pub id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BookmarkEnd {
|
impl BookmarkEnd {
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||||
pub struct BookmarkStart {
|
pub struct BookmarkStart {
|
||||||
id: usize,
|
pub id: usize,
|
||||||
name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BookmarkStart {
|
impl BookmarkStart {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::documents::BuildXML;
|
use crate::documents::BuildXML;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||||
pub struct DocId {
|
pub struct DocId {
|
||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,15 @@ impl DocId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for DocId {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BuildXML for DocId {
|
impl BuildXML for DocId {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let b = XMLBuilder::new();
|
let b = XMLBuilder::new();
|
||||||
|
|
|
@ -129,6 +129,11 @@ impl Docx {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn settings(mut self, s: Settings) -> Self {
|
||||||
|
self.settings = s;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
|
pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
|
||||||
if p.has_numbering {
|
if p.has_numbering {
|
||||||
// If this document has numbering, set numberings.xml to document_rels.
|
// If this document has numbering, set numberings.xml to document_rels.
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use xml::attribute::OwnedAttribute;
|
||||||
|
use xml::reader::EventReader;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl ElementReader for BookmarkEnd {
|
||||||
|
fn read<R: Read>(
|
||||||
|
_r: &mut EventReader<R>,
|
||||||
|
attrs: &[OwnedAttribute],
|
||||||
|
) -> Result<Self, ReaderError> {
|
||||||
|
let mut id: Option<usize> = None;
|
||||||
|
for a in attrs {
|
||||||
|
let local_name = &a.name.local_name;
|
||||||
|
if local_name == "id" {
|
||||||
|
id = Some(usize::from_str(&a.value)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(id) = id {
|
||||||
|
Ok(BookmarkEnd::new(id))
|
||||||
|
} else {
|
||||||
|
Err(ReaderError::XMLReadError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use xml::attribute::OwnedAttribute;
|
||||||
|
use xml::reader::EventReader;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl ElementReader for BookmarkStart {
|
||||||
|
fn read<R: Read>(
|
||||||
|
_r: &mut EventReader<R>,
|
||||||
|
attrs: &[OwnedAttribute],
|
||||||
|
) -> Result<Self, ReaderError> {
|
||||||
|
let mut id: Option<usize> = None;
|
||||||
|
let mut name: Option<String> = None;
|
||||||
|
|
||||||
|
for a in attrs {
|
||||||
|
let local_name = &a.name.local_name;
|
||||||
|
if local_name == "id" {
|
||||||
|
id = Some(usize::from_str(&a.value)?);
|
||||||
|
} else if local_name == "name" {
|
||||||
|
name = Some(a.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if id.is_none() || name.is_none() {
|
||||||
|
return Err(ReaderError::XMLReadError);
|
||||||
|
}
|
||||||
|
Ok(BookmarkStart::new(id.unwrap(), name.unwrap()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,16 @@ impl FromXML for Document {
|
||||||
doc = doc.add_table(t);
|
doc = doc.add_table(t);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
XMLElement::BookmarkStart => {
|
||||||
|
let s = BookmarkStart::read(&mut parser, &attributes)?;
|
||||||
|
doc = doc.add_bookmark_start(s.id, s.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XMLElement::BookmarkEnd => {
|
||||||
|
let e = BookmarkEnd::read(&mut parser, &attributes)?;
|
||||||
|
doc = doc.add_bookmark_end(e.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
mod a_graphic;
|
mod a_graphic;
|
||||||
mod a_graphic_data;
|
mod a_graphic_data;
|
||||||
mod attributes;
|
mod attributes;
|
||||||
|
mod bookmark_end;
|
||||||
|
mod bookmark_start;
|
||||||
mod delete;
|
mod delete;
|
||||||
mod document;
|
mod document;
|
||||||
mod document_rels;
|
mod document_rels;
|
||||||
|
@ -19,6 +21,7 @@ mod read_zip;
|
||||||
mod rels;
|
mod rels;
|
||||||
mod run;
|
mod run;
|
||||||
mod run_property;
|
mod run_property;
|
||||||
|
mod settings;
|
||||||
mod style;
|
mod style;
|
||||||
mod styles;
|
mod styles;
|
||||||
mod table;
|
mod table;
|
||||||
|
@ -49,6 +52,8 @@ const STYLE_RELATIONSHIP_TYPE: &str =
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||||
const NUMBERING_RELATIONSHIP_TYPE: &str =
|
const NUMBERING_RELATIONSHIP_TYPE: &str =
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
|
||||||
|
const SETTINGS_TYPE: &str =
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
|
||||||
|
|
||||||
pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
||||||
let cur = Cursor::new(buf);
|
let cur = Cursor::new(buf);
|
||||||
|
@ -101,5 +106,16 @@ pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
||||||
docx = docx.numberings(nums);
|
docx = docx.numberings(nums);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read settings
|
||||||
|
let settings_path = rels.find_target_path(SETTINGS_TYPE);
|
||||||
|
if let Some(settings_path) = settings_path {
|
||||||
|
let data = read_zip(
|
||||||
|
&mut archive,
|
||||||
|
settings_path.to_str().expect("should have settings"),
|
||||||
|
)?;
|
||||||
|
let settings = Settings::from_xml(&data[..])?;
|
||||||
|
docx = docx.settings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(docx)
|
Ok(docx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,36 +42,13 @@ impl ElementReader for Paragraph {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
XMLElement::BookmarkStart => {
|
XMLElement::BookmarkStart => {
|
||||||
let mut id: Option<usize> = None;
|
let s = BookmarkStart::read(r, &attributes)?;
|
||||||
let mut name: Option<String> = None;
|
p = p.add_bookmark_start(s.id, s.name);
|
||||||
|
|
||||||
for a in attributes {
|
|
||||||
let local_name = &a.name.local_name;
|
|
||||||
if local_name == "id" {
|
|
||||||
id = Some(usize::from_str(&a.value)?);
|
|
||||||
} else if local_name == "name" {
|
|
||||||
name = Some(a.value.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if id.is_none() || name.is_none() {
|
|
||||||
return Err(ReaderError::XMLReadError);
|
|
||||||
}
|
|
||||||
p = p.add_bookmark_start(id.unwrap(), name.unwrap());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
XMLElement::BookmarkEnd => {
|
XMLElement::BookmarkEnd => {
|
||||||
let mut id: Option<usize> = None;
|
let e = BookmarkEnd::read(r, &attributes)?;
|
||||||
for a in attributes {
|
p = p.add_bookmark_end(e.id);
|
||||||
let local_name = &a.name.local_name;
|
|
||||||
if local_name == "id" {
|
|
||||||
id = Some(usize::from_str(&a.value)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(id) = id {
|
|
||||||
p = p.add_bookmark_end(id);
|
|
||||||
} else {
|
|
||||||
return Err(ReaderError::XMLReadError);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
XMLElement::CommentRangeStart => {
|
XMLElement::CommentRangeStart => {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use xml::reader::{EventReader, XmlEvent};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::reader::{FromXML, ReaderError};
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
impl FromXML for Settings {
|
||||||
|
fn from_xml<R: Read>(reader: R) -> Result<Self, ReaderError> {
|
||||||
|
let mut parser = EventReader::new(reader);
|
||||||
|
let mut settings = Self::default();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let e = parser.next();
|
||||||
|
match e {
|
||||||
|
Ok(XmlEvent::StartElement {
|
||||||
|
attributes, name, ..
|
||||||
|
}) => {
|
||||||
|
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||||
|
if let XMLElement::DocId = e {
|
||||||
|
for a in attributes {
|
||||||
|
if let Some(prefix) = a.name.prefix {
|
||||||
|
let local_name = &a.name.local_name;
|
||||||
|
// Ignore w14:val
|
||||||
|
if local_name == "val" && prefix == "w15" {
|
||||||
|
settings = settings.doc_id(
|
||||||
|
&a.value.to_owned().replace("{", "").replace("}", ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||||
|
let e = XMLElement::from_str(&name.local_name).unwrap();
|
||||||
|
if let XMLElement::Settings = e {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndDocument { .. }) => break,
|
||||||
|
Err(_) => return Err(ReaderError::XMLReadError),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(settings)
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,7 @@ pub enum XMLElement {
|
||||||
StartOverride,
|
StartOverride,
|
||||||
Level,
|
Level,
|
||||||
Numbering,
|
Numbering,
|
||||||
|
Settings,
|
||||||
Num,
|
Num,
|
||||||
Start,
|
Start,
|
||||||
NumberFormat,
|
NumberFormat,
|
||||||
|
@ -94,6 +95,7 @@ pub enum XMLElement {
|
||||||
Drawing,
|
Drawing,
|
||||||
TxbxContent,
|
TxbxContent,
|
||||||
Pict,
|
Pict,
|
||||||
|
DocId,
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +228,7 @@ impl FromStr for XMLElement {
|
||||||
"abstractNumId" => Ok(XMLElement::AbstractNumberingId),
|
"abstractNumId" => Ok(XMLElement::AbstractNumberingId),
|
||||||
"lvl" => Ok(XMLElement::Level),
|
"lvl" => Ok(XMLElement::Level),
|
||||||
"numbering" => Ok(XMLElement::Numbering),
|
"numbering" => Ok(XMLElement::Numbering),
|
||||||
|
"settings" => Ok(XMLElement::Settings),
|
||||||
"num" => Ok(XMLElement::Num),
|
"num" => Ok(XMLElement::Num),
|
||||||
"start" => Ok(XMLElement::Start),
|
"start" => Ok(XMLElement::Start),
|
||||||
"numFmt" => Ok(XMLElement::NumberFormat),
|
"numFmt" => Ok(XMLElement::NumberFormat),
|
||||||
|
@ -240,6 +243,7 @@ impl FromStr for XMLElement {
|
||||||
"pict" => Ok(XMLElement::Pict),
|
"pict" => Ok(XMLElement::Pict),
|
||||||
"lvlOverride" => Ok(XMLElement::LvlOverride),
|
"lvlOverride" => Ok(XMLElement::LvlOverride),
|
||||||
"startOverride" => Ok(XMLElement::StartOverride),
|
"startOverride" => Ok(XMLElement::StartOverride),
|
||||||
|
"docId" => Ok(XMLElement::DocId),
|
||||||
_ => Ok(XMLElement::Unsupported),
|
_ => Ok(XMLElement::Unsupported),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,11 @@
|
||||||
import { ParagraphJSON } from "./paragraph";
|
import { ParagraphJSON, BookmarkStartJSON, BookmarkEndJSON } from "./paragraph";
|
||||||
import { TableJSON } from "./table";
|
import { TableJSON } from "./table";
|
||||||
|
|
||||||
export type DocumentChildJSON = ParagraphJSON | TableJSON;
|
export type DocumentChildJSON =
|
||||||
|
| ParagraphJSON
|
||||||
|
| TableJSON
|
||||||
|
| BookmarkStartJSON
|
||||||
|
| BookmarkEndJSON;
|
||||||
|
|
||||||
export type DocumentJSON = {
|
export type DocumentJSON = {
|
||||||
children: DocumentChildJSON[];
|
children: DocumentChildJSON[];
|
||||||
|
|
|
@ -35,6 +35,8 @@ export type DocxJSON = {
|
||||||
};
|
};
|
||||||
numberings: NumberingsJSON;
|
numberings: NumberingsJSON;
|
||||||
settings: {
|
settings: {
|
||||||
|
// w15:docId
|
||||||
|
docId: string | null;
|
||||||
defaultTabStop: number;
|
defaultTabStop: number;
|
||||||
zoom: number;
|
zoom: number;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue