fix: outline lvl (#356)

* fix: outline lvl

* refactor

* fix test
main
bokuweb 2021-10-20 16:37:51 +09:00 committed by GitHub
parent 0ff716318a
commit 00e01479e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 4640 additions and 112 deletions

View File

@ -1,16 +1,16 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
use serde::Serialize;
use serde::*;
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
#[derive(Debug, Clone, PartialEq)]
pub struct OutlineLvl {
pub v: usize,
}
impl OutlineLvl {
pub fn new(v: usize) -> OutlineLvl {
assert!(v < 10, "outline level should be less than 10");
OutlineLvl { v }
}
}
@ -24,15 +24,25 @@ impl BuildXML for OutlineLvl {
}
}
impl Serialize for OutlineLvl {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.v as u32)
}
}
#[cfg(test)]
mod tests {
use crate::{BuildXML, OutlineLvl};
#[test]
fn test_outline_lvl_build(){
fn test_outline_lvl_build() {
let bytes = OutlineLvl::new(1).build();
assert_eq!(std::str::from_utf8(&bytes).unwrap(),r#"<w:outlineLvl w:val="1" />"#);
assert_eq!(
std::str::from_utf8(&bytes).unwrap(),
r#"<w:outlineLvl w:val="1" />"#
);
}
}

View File

@ -203,12 +203,12 @@ impl Paragraph {
self
}
pub(crate) fn hanging_chars(mut self, chars: i32) -> Paragraph {
pub fn hanging_chars(mut self, chars: i32) -> Paragraph {
self.property = self.property.hanging_chars(chars);
self
}
pub(crate) fn first_line_chars(mut self, chars: i32) -> Paragraph {
pub fn first_line_chars(mut self, chars: i32) -> Paragraph {
self.property = self.property.first_line_chars(chars);
self
}
@ -239,7 +239,7 @@ impl Paragraph {
self
}
pub(crate) fn run_property(mut self, p: RunProperty) -> Self {
pub fn run_property(mut self, p: RunProperty) -> Self {
self.property.run_property = p;
self
}

View File

@ -105,6 +105,9 @@ impl ParagraphProperty {
}
pub fn outline_lvl(mut self, v: usize) -> Self {
if v >= 10 {
return self;
}
self.outline_lvl = Some(OutlineLvl::new(v));
self
}

View File

@ -111,16 +111,21 @@ impl Style {
self
}
pub(crate) fn hanging_chars(mut self, chars: i32) -> Self {
pub fn hanging_chars(mut self, chars: i32) -> Self {
self.paragraph_property = self.paragraph_property.hanging_chars(chars);
self
}
pub(crate) fn first_line_chars(mut self, chars: i32) -> Self {
pub fn first_line_chars(mut self, chars: i32) -> Self {
self.paragraph_property = self.paragraph_property.first_line_chars(chars);
self
}
pub fn outline_lvl(mut self, l: usize) -> Self {
self.paragraph_property = self.paragraph_property.outline_lvl(l);
self
}
pub fn table_property(mut self, p: TableProperty) -> Self {
self.table_property = p;
self

View File

@ -25,6 +25,7 @@ mod mc_fallback;
mod numbering_property;
mod numberings;
mod paragraph;
mod paragraph_property;
mod read_zip;
mod rels;
mod run;

View File

@ -7,7 +7,6 @@ use xml::reader::{EventReader, XmlEvent};
use super::*;
use super::attributes::*;
use crate::types::*;
impl ElementReader for Paragraph {
fn read<R: Read>(
@ -71,63 +70,14 @@ impl ElementReader for Paragraph {
}
continue;
}
XMLElement::Indent => {
let (start, end, special, start_chars, hanging_chars, first_line_chars) =
read_indent(&attributes)?;
p = p.indent(start, special, end, start_chars);
if let Some(chars) = hanging_chars {
p = p.hanging_chars(chars);
}
if let Some(chars) = first_line_chars {
p = p.first_line_chars(chars);
// pPr
XMLElement::ParagraphProperty => {
if let Ok(pr) = ParagraphProperty::read(r, attrs) {
p.has_numbering = pr.numbering_property.is_some();
p.property = pr;
}
continue;
}
XMLElement::Spacing => {
let (before, after, line, spacing_type) =
attributes::line_spacing::read_line_spacing(&attributes)?;
p = p.line_spacing(before, after, line, spacing_type);
continue;
}
XMLElement::Justification => {
p = p.align(AlignmentType::from_str(&attributes[0].value)?);
continue;
}
XMLElement::ParagraphStyle => {
p = p.style(&attributes[0].value);
continue;
}
XMLElement::DivId => {
if let Some(val) = read_val(&attributes) {
p.property.div_id = Some(val)
}
continue;
}
XMLElement::NumberingProperty => {
let num_pr = NumberingProperty::read(r, attrs)?;
if num_pr.id.is_some() && num_pr.level.is_some() {
p = p.numbering(num_pr.id.unwrap(), num_pr.level.unwrap());
}
continue;
}
XMLElement::RunProperty => {
let run_pr = RunProperty::read(r, attrs)?;
p = p.run_property(run_pr);
continue;
}
XMLElement::KeepNext => {
p.property.keep_next = true;
}
XMLElement::KeepLines => {
p.property.keep_lines = true;
}
XMLElement::PageBreakBefore => {
p.property.page_break_before = true;
}
XMLElement::WindowControl => {
p.property.window_control = true;
}
_ => {}
}
}
@ -148,6 +98,7 @@ impl ElementReader for Paragraph {
mod tests {
use super::*;
use crate::types::*;
#[cfg(test)]
use pretty_assertions::assert_eq;

View File

@ -0,0 +1,111 @@
use std::io::Read;
use std::str::FromStr;
use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};
use super::*;
use super::attributes::*;
use crate::types::*;
impl ElementReader for ParagraphProperty {
fn read<R: Read>(
r: &mut EventReader<R>,
attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> {
let mut p = ParagraphProperty::new();
loop {
let e = r.next();
match e {
Ok(XmlEvent::StartElement {
attributes, name, ..
}) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
ignore::ignore_element(e.clone(), XMLElement::ParagraphPropertyChange, r);
match e {
XMLElement::Indent => {
let (start, end, special, start_chars, hanging_chars, first_line_chars) =
read_indent(&attributes)?;
p = p.indent(start, special, end, start_chars);
if let Some(chars) = hanging_chars {
p = p.hanging_chars(chars);
}
if let Some(chars) = first_line_chars {
p = p.first_line_chars(chars);
}
continue;
}
XMLElement::Spacing => {
let (before, after, line, spacing_type) =
attributes::line_spacing::read_line_spacing(&attributes)?;
p = p.line_spacing(before, after, line, spacing_type);
continue;
}
XMLElement::Justification => {
if let Ok(v) = AlignmentType::from_str(&attributes[0].value) {
p = p.align(v);
}
continue;
}
XMLElement::ParagraphStyle => {
p = p.style(&attributes[0].value);
continue;
}
XMLElement::RunProperty => {
if let Ok(run_pr) = RunProperty::read(r, attrs) {
p.run_property = run_pr;
}
continue;
}
XMLElement::DivId => {
if let Some(val) = read_val(&attributes) {
p.div_id = Some(val)
}
continue;
}
XMLElement::NumberingProperty => {
let num_pr = NumberingProperty::read(r, attrs)?;
if num_pr.id.is_some() && num_pr.level.is_some() {
p = p.numbering(num_pr.id.unwrap(), num_pr.level.unwrap());
}
continue;
}
XMLElement::OutlineLvl => {
if let Some(val) = read_val(&attributes) {
if let Ok(val) = usize::from_str(&val) {
p = p.outline_lvl(val);
}
}
continue;
}
XMLElement::KeepNext => {
p.keep_next = true;
}
XMLElement::KeepLines => {
p.keep_lines = true;
}
XMLElement::PageBreakBefore => {
p.page_break_before = true;
}
XMLElement::WindowControl => {
p.window_control = true;
}
_ => {}
}
}
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
if e == XMLElement::ParagraphProperty {
return Ok(p);
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
}
}
}

View File

@ -43,22 +43,10 @@ impl ElementReader for Style {
continue;
}
// pPr
XMLElement::Indent => {
let (start, end, special, start_chars, hanging_chars, first_line_chars) =
read_indent(&attributes)?;
style = style.indent(start, special, end, start_chars);
if let Some(chars) = hanging_chars {
style = style.hanging_chars(chars);
XMLElement::ParagraphProperty => {
if let Ok(pr) = ParagraphProperty::read(r, attrs) {
style.paragraph_property = pr;
}
if let Some(chars) = first_line_chars {
style = style.first_line_chars(chars);
}
continue;
}
XMLElement::Justification => {
style = style.align(AlignmentType::from_str(&attributes[0].value)?);
continue;
}
// rPr

View File

@ -10,6 +10,7 @@ use crate::reader::ReaderError;
pub enum XMLElement {
Body,
Paragraph,
ParagraphProperty,
Run,
RunProperty,
Color,
@ -40,6 +41,7 @@ pub enum XMLElement {
IndentLevel,
NumberingId,
Justification,
OutlineLvl,
Insert,
KeepNext,
KeepLines,
@ -205,6 +207,7 @@ impl FromStr for XMLElement {
match s {
"body" => Ok(XMLElement::Body),
"p" => Ok(XMLElement::Paragraph),
"pPr" => Ok(XMLElement::ParagraphProperty),
"r" => Ok(XMLElement::Run),
"rPr" => Ok(XMLElement::RunProperty),
"rPrChange" => Ok(XMLElement::RunPropertyChange),
@ -300,6 +303,7 @@ impl FromStr for XMLElement {
"lvlText" => Ok(XMLElement::LevelText),
"lvlRestart" => Ok(XMLElement::LevelRestart),
"lvlJc" => Ok(XMLElement::LevelJustification),
"outlineLvl" => Ok(XMLElement::OutlineLvl),
"numStyleLink" => Ok(XMLElement::NumStyleLink),
"styleLink" => Ok(XMLElement::StyleLink),
"vAlign" => Ok(XMLElement::VAlign),

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

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

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

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,7 @@
import { RunJSON, RunPropertyJSON } from "./run";
import { IndentJSON } from "./indent";
import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
import {LineSpacingJSON} from "./line_spacing";
import { LineSpacingJSON } from "./line_spacing";
export type ParagraphChildJSON =
| RunJSON
@ -29,6 +29,7 @@ export type ParagraphPropertyJSON = {
keepLines: boolean;
pageBreakBefore: boolean;
windowControl: boolean;
outlineLvl: number | null;
};
export type ParagraphJSON = {

File diff suppressed because it is too large Load Diff

View File

@ -64,9 +64,13 @@ describe("reader", () => {
});
test("should read line spacing docx", () => {
const buffer = readFileSync(
"../fixtures/line_spacing/line_spacing.docx"
);
const buffer = readFileSync("../fixtures/line_spacing/line_spacing.docx");
const json = w.readDocx(buffer);
expect(json).toMatchSnapshot();
});
test("should read outlineLvl docx", () => {
const buffer = readFileSync("../fixtures/outline_lvl/outline_lvl.docx");
const json = w.readDocx(buffer);
expect(json).toMatchSnapshot();
});
@ -347,8 +351,8 @@ describe("writer", () => {
test("should write line spacing", () => {
const p = new w.Paragraph()
.addRun(new w.Run().addText("Hello "))
.lineSpacing(100, "", 100, 1);
.addRun(new w.Run().addText("Hello "))
.lineSpacing(100, "", 100, 1);
const buffer = new w.Docx().addParagraph(p).build();
writeFileSync("../output/line_spacing.docx", buffer);
const z = new Zip(Buffer.from(buffer));

Binary file not shown.