Read docid and bookmark (#138)

* feat: Add document bookmark reader

* feat: Add docId reader
main
bokuweb 2020-09-07 15:46:23 +09:00 committed by GitHub
parent 9eec10e374
commit d2c1417c98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 172 additions and 40 deletions

View File

@ -5,7 +5,7 @@ use crate::xml_builder::*;
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct BookmarkEnd {
id: usize,
pub id: usize,
}
impl BookmarkEnd {

View File

@ -5,8 +5,8 @@ use crate::xml_builder::*;
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct BookmarkStart {
id: usize,
name: String,
pub id: usize,
pub name: String,
}
impl BookmarkStart {

View File

@ -1,9 +1,9 @@
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, Serializer};
use crate::documents::BuildXML;
use crate::xml_builder::*;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct DocId {
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 {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();

View File

@ -129,6 +129,11 @@ impl Docx {
self
}
pub fn settings(mut self, s: Settings) -> Self {
self.settings = s;
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.

View File

@ -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)
}
}
}

View File

@ -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()))
}
}

View File

@ -28,6 +28,16 @@ impl FromXML for Document {
doc = doc.add_table(t);
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;
}
_ => {}
}
}

View File

@ -1,6 +1,8 @@
mod a_graphic;
mod a_graphic_data;
mod attributes;
mod bookmark_end;
mod bookmark_start;
mod delete;
mod document;
mod document_rels;
@ -19,6 +21,7 @@ mod read_zip;
mod rels;
mod run;
mod run_property;
mod settings;
mod style;
mod styles;
mod table;
@ -49,6 +52,8 @@ 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";
const SETTINGS_TYPE: &str =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
let cur = Cursor::new(buf);
@ -101,5 +106,16 @@ pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
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)
}

View File

@ -42,36 +42,13 @@ impl ElementReader for Paragraph {
continue;
}
XMLElement::BookmarkStart => {
let mut id: Option<usize> = None;
let mut name: Option<String> = None;
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());
let s = BookmarkStart::read(r, &attributes)?;
p = p.add_bookmark_start(s.id, s.name);
continue;
}
XMLElement::BookmarkEnd => {
let mut id: Option<usize> = None;
for a in attributes {
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);
}
let e = BookmarkEnd::read(r, &attributes)?;
p = p.add_bookmark_end(e.id);
continue;
}
XMLElement::CommentRangeStart => {

View File

@ -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)
}
}

View File

@ -83,6 +83,7 @@ pub enum XMLElement {
StartOverride,
Level,
Numbering,
Settings,
Num,
Start,
NumberFormat,
@ -94,6 +95,7 @@ pub enum XMLElement {
Drawing,
TxbxContent,
Pict,
DocId,
Unsupported,
}
@ -226,6 +228,7 @@ impl FromStr for XMLElement {
"abstractNumId" => Ok(XMLElement::AbstractNumberingId),
"lvl" => Ok(XMLElement::Level),
"numbering" => Ok(XMLElement::Numbering),
"settings" => Ok(XMLElement::Settings),
"num" => Ok(XMLElement::Num),
"start" => Ok(XMLElement::Start),
"numFmt" => Ok(XMLElement::NumberFormat),
@ -240,6 +243,7 @@ impl FromStr for XMLElement {
"pict" => Ok(XMLElement::Pict),
"lvlOverride" => Ok(XMLElement::LvlOverride),
"startOverride" => Ok(XMLElement::StartOverride),
"docId" => Ok(XMLElement::DocId),
_ => 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

View File

@ -1,7 +1,11 @@
import { ParagraphJSON } from "./paragraph";
import { ParagraphJSON, BookmarkStartJSON, BookmarkEndJSON } from "./paragraph";
import { TableJSON } from "./table";
export type DocumentChildJSON = ParagraphJSON | TableJSON;
export type DocumentChildJSON =
| ParagraphJSON
| TableJSON
| BookmarkStartJSON
| BookmarkEndJSON;
export type DocumentJSON = {
children: DocumentChildJSON[];

View File

@ -35,6 +35,8 @@ export type DocxJSON = {
};
numberings: NumberingsJSON;
settings: {
// w15:docId
docId: string | null;
defaultTabStop: number;
zoom: number;
};