驾校理论考试系统之数据提取三(2)

DocToDataXml.zip 1

目的将各个word(选择,判断,多选)中的数据填入data.xml

项目:微软开源CodePlex,PowerTools for Open XML

下载PowerTools Core 2.2

解压缩,然后打开 ,然后设置未启动项目

OpenXmlPowerTools.zip 1 OpenXmlPowerTools.sln

 

然后分析代码,我们可以看到在ExampleHtmlConverter03Images项目内有一个Test.docx文档,这是用来测试的文档。运行看看能不能正常运行。

可以看到在项目ExampleHtmlConverter03Images中生成了test.html文档。

在这里我们要补一补,html语法和open xml的用法。

首先要安装Open xml SDK,有106.4 MB大小,其中安装目录中有一个工具叫做OpenXmlSdkTool,可以查看Word文档,docx,我们用来查看一下Test.docx。

点击Open File找到Test.docx,然后将树状节点图展开到下图形式

reflect code,就会出现出现代码,这些都是自动生成的,我们会发现,原来我们经常用到的docx居然是这样的,各一个XML文档没有太大区别。

其实,还有你不知道的,那就是word文档其实是一个zip,压缩文件。

我们将Test.docx转换成Test.zip,然后打开压缩文件如图:

打开其中的document.xml,发现

第一个W:p中w:t中的那句话对应,word文档中的第一句话。我们猜测,W:p,p指的是Paragraph一段,而W:t,t则是Text文本。正如前面那个工具展示的那个图。

再来看看已经转换好的html文档,

我们发现,与document.xml显示的类似,第一句话也被包含在<p></p>中,而且代码简洁了不知道多少。

由此可知,要把Docx转化为html无非是把图片和段中的文字提取出来,然后显示在html的<p></p>和<img/>中。

既然这样,那我们为什么只要找到项目ExampleHtmlConverter03Images,提取段文字和图片的地方,然后将其填入data.xml中就达到了我们的目的了。

我们现在来断点调试吧!

值得注意的是,你可能要补一下LINQ,语言集成查询(Language INtegrated Query)方面的知识!!

在main方法出设置一个断点,按F11会达到这个地方,如图,我们发现=>这个图标看不懂,其实这是linq中的语法,表示的是将imageInfo

这个参数传到=>后面的语句进行循环处理,就是有多少个imageInfo就处理多少次。随后我们发现关键词,png,jpeg,这提示我们下面的语句是在保存图片,到html文件中的<img/>中。

看到黄色区域最后部分,我们发现的确是这样子的,兴奋了吧!!哈哈

再来看看是如何保存<p></P>段文字的,继续调试

既然是htmlConverter,所以我们首先在 HtmlConverter.cs中查看,发现

这里这段话,Transform every paragraph,猜测应该是这吧,设个断点试试,不断F11

这是我们惊喜的发现,居然有一个变量pt与文档中的第一句话是一样的,这是我们要找的段落文字找到了!

现在我们该考虑怎么将这些图片和文字保存到data.xml中了!!!

我们新建一个C#控制台应用程序,DocToDataXml。

将先前项目ExampleHtmlConverter03Images中需要的HtmlConverterImages.cs文件和OpenXmlPowerTools项目中的所有cs文件添加到项目DocToDataXml。并且添加缺少的dll引用和文件Test.dll.并且删除program.cs,以避免有两个入口点。

调试是否成功运行。调试成功后!

再来分析一下试题,例如一个单选文档中有很多道题目,如果要处理这些数据,我们需要一道题一道题的处理,那么必须有一个标志,来识别是否一道题已经处理完了,观察题目可以清楚的发现,每道题前面都有1.,2.,3.。。。。。等等,那么就这个标志,不知道在openxml是怎么区分了,我们用openxml tool来看看!!

为了对比有1.,和没有的区别,新建一个docx,一个带编号,一个不带

  1. 呵呵

呵呵

 

 

 

 

 

 

用openxml tool查看:发现带编号的段落,多段属性,属性中又有编号属性,由此可区分!!

现在我们来正式处理试题文档,复制所有试题到项目bin/debug目录下进行处理!!修改HtmlConverterImages.cs源文件中修改

string sourceDocumentFileName = @"驾校考试试题\安全行车常识\安全避让\单选.docx";

,运行成功后,打开单选.html,发现出现乱码,说明需要修改最后保存html文件的格式,所以修改HtmlConverterImages.cs源文件最后这段代码,添加Encoding.UTF8

File.WriteAllText(fileInfo.Directory.FullName + "/" + fileInfo.Name.Substring(0,

fileInfo.Name.Length - fileInfo.Extension.Length) + ".html",

html.ToStringNewLineOnAttributes(),Encoding.UTF8);

 

修改后得到预期中的html文件

接下来,定义保存一道题目的变量在

Program类中定义静态变量数组str和静态变量图片文件名

public static ArrayList str = new ArrayList();

public static string imageFileName;

在先前找到的保存<p></p>的地方ListItemRetriever.cs类,方法RetrieveListItem

中添加如下代码,用来保存题目和选项。

if (pt != " " && pt != "" && pt != " " && pt != " " && pt != " ")

{

Console.WriteLine(pt);

Program.str.Add(pt);

}

去掉main方法中 string imageFileName = imageDirectoryName + "/image" +

imageCounter.ToString() + "." + extension;

前面的string因为我们已经在此类中定义了,相同的静态变量!以此来保存

图片文件地址!!

提示:由于代码行比较多,可以定义书签,按两下ctrl –k,

左边出现方形框,提示此处为书签,在此文件任意位置,按F2即可跳到此处!!

 

在HtmlConverter.cs类,方法ConvertToHtmlTransform添加如下代码用来判断一道题是终结

//控制序号属性值,令其换行

if (element.Name == W.p)

{

if (element.Elements(W.pPr).Elements(W.numPr).FirstOrDefault() != null)

{

string numId = element.Elements(W.pPr).Elements(W.numPr).Elements(W.numId)

.First().FirstAttribute.Value;

if (numId == "1")

{

Console.Write("\n\n");

//如果str中已经插入了题目和选项,则调用InsertSomeNode写入data.xml,并将strimageFileName清零

if (Program.str.Count > 1)

{

Console.WriteLine(Program.strFileName);

Program.str.Add(Program.imageFileName);

Program.InsertSomeNode(Program.str, Program.strFileName, Program.i++);

Program.imageFileName = null;

Program.str.Clear();

}

}

}

}

可以看到我们判断这道题是否结束是通过查找W.p -> w.pPr->numId == '1'来判断是否结束的!!

然后利用此方法

public static void InsertSomeNode(ArrayList str, string locateFullName, int NumId)

插入题目和选项及图片地址到data.xml!!

其中有些地方需要小幅改动,具体请查看源代码!

运行结果如下:

接下来,我们要做的是将所有文档一次都插入到data.xml!

那首先得检索到所有文档,我们使用此方法

//检索文档中特定格式的文档pattenr="*.docx"

public static void GetFiles(DirectoryInfo directory, string pattern)

{

if (directory.Exists || pattern.Trim() != string.Empty)

{

 

foreach (FileInfo info in directory.GetFiles(pattern))

{

//对单个文档的操作

//Console.WriteLine(info.FullName);

//Console.WriteLine(info.FullName.TrimEnd(".docx".ToCharArray())+".html");

DocToHtml(info.FullName);

//SpliteHtml(info.FullName.TrimEnd(".docx".ToCharArray()) + ".html");

}

foreach (DirectoryInfo info in directory.GetDirectories())

{

GetFiles(info, pattern);

}

}

}

至于docTOhtml,是将先前处理单个文档的过程全部放到一个方法中,

static void Main(string[] args)

{

string strPath ="驾校考试试题";

DirectoryInfo doc = new DirectoryInfo(strPath);

Program.GetFiles(doc, "*.docx");

}

Main方法中如上显示的,点击运行,彻底结束这个蛋疼的过程了!!

将近一万行的data.xml

不过我们注意到,好像还有动画文件名没有插入文档,下面在来看看吧!!

我们可以看到动画在<Title></Title>之间,我们要做的就是找到带有动画的节点Title

XmlNodeList Xlist = doc.SelectNodes("//Title");

用c#中的正则表达式提取动画名

foundMatch = Regex.Match(str, "动画[0-9]{1,}");

然后在把动画*.AVI插入到data.xml的source->Video中

XmlElement elem1 = doc.CreateElement("Video");

elem1.InnerText = foundMatch.Value + ".avi";//@"D:\驾校考试题库\AVI文件\" +

elem.AppendChild(elem1);

具体代码参看源文件!!

点击执行!

找到22个动画

posted @ 2012-07-18 23:31  zuizuihao  阅读(621)  评论(0)    收藏  举报