OfficeXml/README.md

235 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OfficeXml
## 概述
将 docx、pptx、xlsx 等文件中的 xml 转为 tsl 对象
```xml
<w:p w14:paraId="6E3ED3BE" w14:textId="77777777" w:rsidR="00C57A1E"
w:rsidRDefault="00C57A1E" w:rsidP="00C27AE9">
<w:pPr>
<w:jc w:val="left" />
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" />
</w:rPr>
<w:t>最小申购、赎回单位</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" />
</w:rPr>
<w:t>(份)</w:t>
</w:r>
</w:p>
```
上述是一个 docx 中的段落的 xml序列化为 tsl 过程如下
```go
uses DocxML; // 上述xml属于DocxML
p := new P(); // 创建一个P对象段落w:p
p.Init(node); // 假设node节点是上面的xml指向的Node对象
p.Deserialize(); // 将node对象的xml序列化到tsl对象
// 序列化完毕后,可直接对应取值
echo p.PPr.Jc.Val; // 输出left
// 如果需要修改内容通过Serialize()回写到node
p.PPr.Jc.Val := "center";
// 回写方法1适合修改单个对象
p.PPr.Jc.Serialize();
// 回写方法2大量修改不同的对象
p.Serialize(); // 或p.PPr.Serialize()
// 在获取存在多个节点的对象时比如上述的w:r对象是复数的则需要通过Rs()获取
// 直接调用Rs()会获取所有的R对象加上索引会获取第N+1个
echo p.Rs(1).T.Text; // 输出:(份)
```
## 基类
`OpenXmlElement.tsf`提供了一些常用的方法,具体可见`tsf`文件
## Unit 单元
- `DocxML`
包含`docx`文件独有的 xml 节点对象,一般 xml 的命名空间是`w`,如`w:p`
- `PptxML`
包含`pptx`文件独有的 xml 节点对象,一般 xml 的命名空间是`p`,如`p:spPr`
- `XlsxML`
包含`xlsx`文件独有的 xml 节点对象
- `DrawingML`
包含`docx,pptx,xlsx`文件图形的 xml 节点对象,一般 xml 的命名空间是`a`,如`a:xfrm`
- `SharedML`
包含`docx,pptx,xlsx`文件共有的 xml 节点对象
- `VML`
[参考链接 1](http://webapp.docx4java.org/OnlineDemo/ecma376/)
[参考链接 2](http://officeopenxml.com/index.php)
## 部件
### Components
一共有三个部件,分别是:
1. `DocxComponents.tsf`docx 文件的各部分 xml 内容
2. `XlsxComponents`xlsx 文件的各部分 xml 内容
3. `PptxComponents`pptx 文件的各部分 xml 内容
以`DocxComponents.tsf`为例,使用这个类,可以获取到对应的 docx 文件的 xml 对象
```go
component := new DocxComponents(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
document.Body.Elements(); // 可以获取document的body下的所有对象列表
// 反序列化后,可进行读写
styles := component.Styles; // 获取styles.xml生成Styles对象
```
document.xml 内容如下
```xml
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex"
xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex"
mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16du wp14">
<w:body>
<w:p w14:paraId="7B19BB62" w14:textId="33E8D5E1" w:rsidR="00B118EF"
w:rsidRDefault="00B118EF" w:rsidP="00B118EF">
<w:pPr>
<w:tabs>
<w:tab w:val="left" w:pos="5670" />
</w:tabs>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" />
</w:rPr>
<w:t>分栏前</w:t>
</w:r>
</w:p>
<w:sectPr w:rsidR="00B118EF" w:rsidSect="002E4343">
<w:type w:val="continuous" />
<w:pgSz w:w="11906" w:h="16838" w:code="9" />
<w:pgMar w:top="1440" w:right="1797" w:bottom="1440" w:left="1797" w:header="851"
w:footer="992" w:gutter="0" />
<w:cols w:space="720" />
<w:docGrid w:type="linesAndChars" w:linePitch="312" />
</w:sectPr>
</w:body>
</w:document>
```
### 单位装饰器 UnitDecorator
每个对象都有一个单位装饰器,能统一转成磅(point)单位(如果有配置属性转换),还能保留原来的接口
每个`ML`都有装饰器`tsf`统一命名是`Unit的名称+UnitDecorator`,如`docx``docx`大部分`xml`隶属于`DocxML`)的`SectPr`对象的装饰器是`SectPrUnitDecorator`
如:有下面一段 xml其中的`pgSz.w = "11906", pgSz.h = "16838"`都需要转换成 point
```xml
<w:sectPr w:rsidR="00B118EF" w:rsidSect="002E4343">
<w:type w:val="continuous" />
<w:pgSz w:w="11906" w:h="16838" w:code="9" />
<w:pgMar w:top="1440" w:right="1797" w:bottom="1440" w:left="1797" w:header="851"
w:footer="992" w:gutter="0" />
<w:cols w:space="720" />
<w:docGrid w:type="linesAndChars" w:linePitch="312" />
</w:sectPr>
```
```go
uses DocxMLUnitDecorator;
component := new Components(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
sect_pr := document.Body.SectPr; // 获取SectPr对象
sect_pr_unit_decorator := new SectPrUnitDecorator(sect_pr); // 装饰器构造需要原本的对象
echo "w = ", sect_pr.PgSz.W; // 输出的是字符串原本的单位是twips
echo "\n";
echo "w = ", sect_pr_unit_decorator.PgSz.W; // 此时输出的是数字类型单位是point
```
### 适配器 Adapter
适配器是通过 key 获取对应的对象,比如样式可以通过样式 ID 获取对应的样式对象
只有部分对象才有适配器(具体可见`autounit/xxxMLAdapter`),比如`DocxML.Styles`的适配器是`StylesAdapter`
styles.xml 部分如下
```xml
<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<w:style w:type="character" w:customStyle="1" w:styleId="a4">
<w:name w:val="页眉 字符" />
<w:basedOn w:val="a0" />
<w:link w:val="a3" />
<w:uiPriority w:val="99" />
<w:rsid w:val="00B118EF" />
<w:rPr>
<w:sz w:val="18" />
<w:szCs w:val="18" />
</w:rPr>
</w:style>
<w:style w:type="character" w:customStyle="1" w:styleId="a6">
<w:name w:val="页脚 字符" />
<w:basedOn w:val="a0" />
<w:link w:val="a5" />
<w:uiPriority w:val="99" />
<w:rsid w:val="00B118EF" />
<w:rPr>
<w:sz w:val="18" />
<w:szCs w:val="18" />
</w:rPr>
</w:style>
</w:styles>
```
```go
uses DocxMLAdapter;
component := new Components(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
styles := document.Styles;
// 现在需要通过styleId获取Style对象
styles_adapter := new StylesAdapter(styles);
// 通过StyleId获取Style对象
style := styles_adapter.GetStyleByStyleId("a6");
echo style.Name; // 输出的是"页脚 字符"
```
### 补充
```xml
<m:r>
<m:rPr>
<m:sty m:val="p" />
</m:rPr>
<a:rPr lang="en-US"
altLang="zh-CN" sz="1100"
i="0" kern="1200">
<a:latin
typeface="Cambria Math"
panose="02040503050406030204"
pitchFamily="18"
charset="0" />
</a:rPr>
<m:t>cos</m:t>
</m:r>
```
由于设计取对象时候不包含前缀,那么同时存在多个`rPr`时,如何区分是哪一个?
取`m:rPr`时,可通过`r.RPr`,这是因为它们的前缀都是`m`,所以可直接获取
取`a:rPr`时,需要指定前缀`a`,通过`r.RPr('a')`,进行获取`RPr`对象