罗曼蒂克是奢侈滴

生命不息,学习不止

导航

小说下载阅读器_章节保存为XML并显示

这篇文章主要是讲程序中对XML,XSLT,XSD,JS的简单应用。

1.当小说的章节都下载完毕,章节内容经过过滤,去除多余的html标记和其它垃圾信息,变成干净的文本内容。怎么保存这些章节内容呢?

1)解决方法:将所有章节依次写入同一个文本文件,并将小说名作为文件名。

优点:
通用性最好,不管是PC平台还是手机、平板电脑都能直接阅读,且人可直接阅读。
缺点:
如果想分离每章或者将文本文件格式转成其它格式,解析相对麻烦。

2)解决方法:将所有章节,分章节依次写入同一个xml文件,并将小说名作为文件名。

优点:
由于xml文件是结构性的,通用性也很强,可轻易转成其它任意格式,且章节之间本身也是分隔的
缺点:
在于由于多了额外的信息,xml会比文本文件稍大一些。

3)解决方法:将将所有章节,分章节写入数据库。

优点:
数据库的优点,不用多说,查询检索很方便。
缺点:
当数据多了,数据库也会变大。

我采用的是第二种方法,原因如下

1.暂时减少对数据库的依赖(后面的进化版,可能会用数据库存储章节内容)
2.虽然文本文件的通用性是最高的,但我需要在window和linux上看小说,或者是手机上,手机上一般都需要安装阅读器,其实很多格式都支持,这个不是问题,关键在于window和linux上阅读,如果只是用普通编辑器来看文本小说,可以看,但是视觉效果真是很烂,为了统一windows和linux上的视觉效果,干脆就用xml作为中间格式,最终都在浏览器里面观看。

2.小说要保存的要素:小说名称,章节名,章节内容,卷名以及其它附加信息

1)XML格式例子如下:

 1 <?xml version="1.0" encoding="GB2312"?>
 2 <Article Name="盘龙" CreateTime="2012-01-01 00:00:00">
 3     <Part Index="第一章 小镇的早晨"  Volume="盘龙之戒">
 4            章节内容.......................
 5     </Part>
 6     <Part Index="第二章 龙血战士家族(上)"  Volume="盘龙之戒">
 7     ;;段落内容........;;段落内容。;;段落内容。;;段落内容。;;段落内容。;;段落内容。;;段落内容。
 8     </Part>
 9     <Part Index="第三章 龙血战士家族(下)"  Volume="盘龙之戒">
10            <img src="http://img.58xs.com/gif/195/195623/18276026/13028469.gif" />//如果有图片就是这样的
11     </Part>
12 </Article>

C#如何将字符串保存为xml,请参考System.Xml命名空间下的类,或者用linq to xml都行,更或者直接string拼凑都可以,代码就不写了。

2)用xsd 来定义xml的schema:

 1 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
 2     <xs:element name="Img">
 3         <xs:complexType>
 4             <xs:attribute name="Src" type="xs:anyURI" use="required"/>
 5         </xs:complexType>
 6     </xs:element>
 7     <xs:element name="Part">
 8         <xs:complexType mixed="true">
 9             <xs:sequence>
10                 <xs:element ref="Img" minOccurs="0" maxOccurs="unbounded"/>
11             </xs:sequence>
12             <xs:attribute name="Index" type="xs:string" use="required"/>
13             <xs:attribute name="Volume" type="xs:string" use="optional"/>
14         </xs:complexType>
15     </xs:element>
16     <xs:element name="Article">
17         <xs:complexType>
18             <xs:sequence>
19                 <xs:element ref="Part" maxOccurs="unbounded"/>
20             </xs:sequence>
21             <xs:attribute name="Name" type="xs:string" use="required"/>
22             <xs:attribute name="CreateTime" type="xs:dateTime" use="optional"/>
23         </xs:complexType>
24     </xs:element>
25 </xs:schema>

以下是基本的解释

Article.Name是小说名称 ,CreateTime是xml文件最后保存时间
Part.Index是章节名称,Volume是卷名
再就是Part的内容要么是文字,要么是Img图片

3.如何显示保存到文件中章节内容呢?这里用xslt将xml文件转化成html进行显示

先显示效果图:

上述两幅图可以看出,显示部分主要分为三大块:

1)第一块是第一幅图的最上的章节索引链接,可以在这块跳转到你需要观看的章节去
2)第二块是第一幅图的下半部分,就是小说的正文,每一章节对应一个区块,每一章节都可以向前一章和后一章跳转。
3)第三块是第二幅图的右半边,红色字的部分,可以对页面背景色和字体,以及页面自动滚动速度进行设置。

当你写好xslt文件的时候,可以在xml文件第一行后面加上一句话区引用这个xslt文件,就可以让xml在浏览器中按照xslt规定显示

<?xml-stylesheet type="text/xsl" href="Article.xslt"?>

下面给出xslt的源码:

  1 <?xml version="1.0" encoding="GB2312"?>
  2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3     <!--
  4     <xsl:import href="function.xsl"/>
  5 -->
  6     <xsl:variable name="SplitToken">;;</xsl:variable>
  7     <xsl:template match="/">
  8         <html>
  9             <head>
 10                 <title>
 11                     <xsl:value-of select="/Article/@Name"/>
 12                 </title>
 13             </head>
 14             <link type="text/css" href="ui_a.css" rel="stylesheet"/>
 15             <body>
 16                 <xsl:choose>
 17                     <xsl:when test="count(/Article/*)>=1">
 18                         <a class="title" name="0">
 19                             <xsl:value-of select="/Article/@Name"/>
 20                         </a>
 21                         <br/>
 22                         <br/>
 23                         <xsl:if test="count(//Part)>1">
 24                             <xsl:call-template name="PartIndex"/>
 25                         </xsl:if>
 26                         <br/>
 27                         <xsl:call-template name="PartList"/>
 28                     </xsl:when>
 29                     <xsl:otherwise>
 30                         <div class="NoPart">
 31                             <xsl:text>无内容,请添加章节</xsl:text>
 32                         </div>
 33                     </xsl:otherwise>
 34                 </xsl:choose>
 35                 <!--this js must be here,if not be here,invalid in IE6\Opear\Chome-->
 36             
 37                 <div class="scroll">
 38                     <input name="scrollspeed" id="scrollspeed" title="Scroll Speed" onchange="javascript:setSpeed();" value="5"/>
 39                     <input name="bgcolor" id="bgcolor" value="#FEF7DA" tilte="Background Color"/>
 40                     <input name="fcolor" id="fcolor" value="#000000" tilte="Font Color"/>
 41                     <input name="Fsize" id="Fsize" value="16pt" tilte="Font Size"/>
 42                     <input type="button" title="Save" value="Save" onclick="javascript:saveSet();"/>
 43                 </div>
 44 
 45                 <script src="Novel.js"/>
 46 
 47             </body>
 48         </html>
 49     </xsl:template>
 50     <xsl:template name="PartIndex">
 51         <div class="roundconner">
 52             <xsl:call-template name="Roundconner">
 53                 <xsl:with-param name="IsTop" select="''"/>
 54             </xsl:call-template>
 55             <div name="Content" id="Content" class="Content">
 56                 <table width="100%">
 57                     <tbody style="text-align : '.'">
 58                         <xsl:for-each select="/Article/Part">
 59                             <xsl:choose>
 60                                 <xsl:when test="position() mod 3=2">
 61                                     <xsl:call-template name="IndexGroup">
 62                                         <xsl:with-param name="th1">
 63                                             <xsl:value-of select="concat(position()-1,$SplitToken)"/>
 64                                             <xsl:value-of select="./preceding-sibling::*[position()=1]/@Index"/>
 65 
 66                                         </xsl:with-param>
 67                                         <xsl:with-param name="th2">
 68                                             <xsl:value-of select="concat(concat(position(),$SplitToken),@Index)"/>
 69                                         </xsl:with-param>
 70                                         <xsl:with-param name="th3">
 71                                             <xsl:value-of select="concat(position()+1,$SplitToken)"/>
 72                                             <xsl:value-of select="./following-sibling::*[position()=1]/@Index"/>
 73                                         </xsl:with-param>
 74                                     </xsl:call-template>
 75                                 </xsl:when>
 76                                 <xsl:when test="(position() mod 3=1) and (position()=last())">
 77                                     <xsl:call-template name="IndexGroup">
 78                                         <xsl:with-param name="th1">
 79                                             <xsl:value-of select="concat(concat(position(),$SplitToken),@Index)"/>
 80                                         </xsl:with-param>
 81                                     </xsl:call-template>
 82                                 </xsl:when>
 83                             </xsl:choose>
 84                         </xsl:for-each>
 85                     </tbody>
 86                 </table>
 87             </div>
 88             <xsl:call-template name="Roundconner">
 89                 <xsl:with-param name="IsTop" select="'1'"/>
 90             </xsl:call-template>
 91         </div>
 92     </xsl:template>
 93     <xsl:template name="IndexGroup">
 94         <xsl:param name="th1" select="''"/>
 95         <xsl:param name="th2" select="''"/>
 96         <xsl:param name="th3" select="''"/>
 97         <tr>
 98             <th>
 99                 <xsl:call-template name="AddLink">
100                     <xsl:with-param name="str" select="$th1"/>
101                 </xsl:call-template>
102                 <xsl:if test="./preceding::*[position()=1]/@Volume">
103                     <font class="Volume">
104                         <xsl:call-template name="AddLink"/>&#160;&#160;[<xsl:value-of select="./preceding::*[position()=1]/@Volume"/>]
105                     </font>
106                 </xsl:if>
107             </th>
108             <th>
109                 <xsl:call-template name="AddLink">
110                     <xsl:with-param name="str" select="$th2"/>
111                 </xsl:call-template>
112                 <xsl:if test="./@Volume">
113                     <font class="Volume">
114                         <xsl:call-template name="AddLink"/>&#160;&#160;[<xsl:value-of select="./@Volume"/>]
115                     </font>
116                 </xsl:if>
117             </th>
118             <th>
119                 <xsl:call-template name="AddLink">
120                     <xsl:with-param name="str" select="$th3"/>
121                 </xsl:call-template>
122                 <xsl:if test="./following::*[position()=1]/@Volume">
123                     <font class="Volume">
124                         <xsl:call-template name="AddLink"/>&#160;&#160;[<xsl:value-of select="./following::*[position()=1]/@Volume"/>]
125                     </font>
126                 </xsl:if>
127             </th>
128         </tr>
129     </xsl:template>
130     <xsl:template name="AddLink">
131         <xsl:param name="str" select="''"/>
132         <a href="#{substring-before($str,$SplitToken)}">
133             <xsl:value-of select="substring-after($str,$SplitToken)"/>
134         </a>
135     </xsl:template>
136     <xsl:template name="PartTitle">
137         <xsl:param name="name" select="''"/>
138         <xsl:param name="pos">0</xsl:param>
139         <div>
140             <a class="PartIndex" name="{$pos}">
141                 <xsl:value-of select="$name"/>
142             </a>
143             <xsl:if test="(count(/Article/*)>1)">
144                 <font class="PartStep">
145                     <a href="#{-1+$pos}">上章</a>
146                     <a href="#{1+$pos}">下章</a>
147                     <a href="#0">返回</a>
148                 </font>
149             </xsl:if>
150         </div>
151     </xsl:template>
152     <xsl:template name="PartList">
153         <div class="roundconner">
154             <xsl:call-template name="Roundconner">
155                 <xsl:with-param name="IsTop" select="''"/>
156             </xsl:call-template>
157             <xsl:for-each select="//Part">
158                 <xsl:call-template name="PartTitle">
159                     <xsl:with-param name="name" select="@Index"/>
160                     <xsl:with-param name="pos" select="position()"/>
161                 </xsl:call-template>
162                 <div name="Content" id="Content" class="Content">
163                     <!-- add img-->
164                     <xsl:if test="(count(./img)>0)">
165                         <div class="imgDiv" style="clear:both">
166                             <xsl:for-each select="./img">
167                                 <xsl:element name="img">
168                                     <xsl:attribute name="src"><xsl:value-of select="@src"/></xsl:attribute>
169                                 </xsl:element>
170                             </xsl:for-each>
171                         </div>
172                     </xsl:if>
173                     <xsl:call-template name="ChangeLine">
174                         <xsl:with-param name="str">
175                             <xsl:choose>
176                                 <xsl:when test="contains(., $SplitToken)">
177                                     <xsl:value-of select="substring-after(., $SplitToken)"/>
178                                 </xsl:when>
179                                 <xsl:otherwise>
180                                     <xsl:value-of select="."/>
181                                 </xsl:otherwise>
182                             </xsl:choose>
183                         </xsl:with-param>
184                         <xsl:with-param name="pat">
185                             <xsl:value-of select="$SplitToken"/>
186                         </xsl:with-param>
187                     </xsl:call-template>
188                 </div>
189                 <xsl:if test="(count(/Article/*)>1) and ( position()!=last())">
190                     <div class="split"/>
191                 </xsl:if>
192             </xsl:for-each>
193             <xsl:call-template name="Roundconner">
194                 <xsl:with-param name="IsTop" select="bot"/>
195             </xsl:call-template>
196         </div>
197     </xsl:template>
198     <xsl:template name="ChangeLine">
199         <xsl:param name="str"/>
200         <xsl:param name="pat"/>
201 &#12288;&#12288;
202         <xsl:choose>
203             <xsl:when test="contains($str, $pat)">
204                 <xsl:if test="not(starts-with($str, $pat))">
205                     <xsl:value-of select="substring-before($str, $pat)"/>
206                     <br/>
207                 </xsl:if>
208                 <xsl:call-template name="ChangeLine">
209                     <xsl:with-param name="str" select="substring-after($str, $pat)"/>
210                     <xsl:with-param name="pat" select="$pat"/>
211                 </xsl:call-template>
212             </xsl:when>
213             <xsl:otherwise>
214                 <xsl:value-of select="$str"/>
215             </xsl:otherwise>
216         </xsl:choose>
217     </xsl:template>
218     <xsl:template name="Roundconner">
219         <xsl:param name="IsTop" select="''"/>
220         <xsl:choose>
221             <xsl:when test="$IsTop=''">
222                 <b class="rtop">
223                     <b class="r1"/>
224                     <b class="r2"/>
225                     <b class="r3"/>
226                     <b class="r4"/>
227                 </b>
228             </xsl:when>
229             <xsl:otherwise>
230                 <b class="rbottom">
231                     <b class="r4"/>
232                     <b class="r3"/>
233                     <b class="r2"/>
234                     <b class="r1"/>
235                 </b>
236             </xsl:otherwise>
237         </xsl:choose>
238     </xsl:template>
239 </xsl:stylesheet>

其中xslt中用到了一点javascript来实现对cookie的读取和自动滚屏功能,这里也给出对应的novel.js代码

  1 var curPos, timer,speed=5;
  2 ////////////
  3 var scrollspeed=document.getElementById("scrollspeed");
  4 var bgcolor=document.getElementById("bgcolor");
  5 var fcolor=document.getElementById("fcolor");
  6 var Fsize=document.getElementById("Fsize");
  7 
  8 function setCookies(cookieName,cookieValue, expirehours)
  9 {
 10   var today = new Date();
 11   var expire = new Date();
 12   expire.setTime(today.getTime() + 3600000 * 356 * 24);
 13   document.cookie = cookieName+'='+escape(cookieValue)+ ';expires='+expire.toGMTString();
 14 }
 15 function ReadCookies(cookieName,obj)
 16 {
 17     var theCookie=''+document.cookie;//alert(document.cookie);
 18     var ind=theCookie.indexOf(cookieName);
 19     if (ind==-1 || cookieName=='') return obj;
 20     var ind1=theCookie.indexOf(';',ind);
 21     if (ind1==-1) ind1=theCookie.length;//alert(ind+"\n"+ind1);
 22     return unescape(theCookie.substring(ind+cookieName.length+1,ind1));
 23 }
 24 function saveSet()
 25 {
 26     setCookies("scrollspeed",scrollspeed.value);
 27 
 28     setCookies("bgcolor",bgcolor.value);
 29     ChangeBgcolor(bgcolor.value);
 30 
 31     setCookies("fcolor",fcolor.value);
 32     ChangeFcolor(fcolor.value);
 33 
 34     setCookies("Fsize",Fsize.value);
 35     ChangeFsize(Fsize.value);
 36 
 37 }
 38 
 39 function Change(obj,index)
 40 {
 41     var oCB=document.getElementsByName('Content');
 42     for(i=0;i<oCB.length;i++)
 43     {
 44             oCB[i].style.backgroundColor=obj;
 45     }
 46 }
 47 function ChangeBgcolor(color)
 48 {
 49     var oCB=document.getElementsByName('Content');
 50     for(i=0;i<oCB.length;i++)
 51     {
 52             oCB[i].style.backgroundColor=color;
 53     }
 54 }
 55 function ChangeFcolor(color)
 56 {
 57     var oCB=document.getElementsByName('Content');
 58 
 59     for(i=0;i<oCB.length;i++)
 60     {
 61 
 62             oCB[i].style.color=color;
 63     }
 64 }
 65 function ChangeFsize(fontSize)
 66 {
 67     var oCB=document.getElementsByName('Content');
 68 
 69     for(i=0;i<oCB.length;i++)
 70     {
 71             oCB[i].style.fontSize =fontSize;
 72     }
 73 }
 74 function loadSet()
 75 {
 76     scrollspeed.value=ReadCookies("scrollspeed",5);
 77     setSpeed();
 78 
 79     bgcolor.value=ReadCookies("bgcolor","#FFFFFF");;
 80     ChangeBgcolor(bgcolor.value);
 81 
 82 
 83     fcolor.value=ReadCookies("fcolor","#000000");;
 84     ChangeFcolor(fcolor.value);
 85 
 86 
 87     Fsize.value=ReadCookies("Fsize","16px");;
 88     ChangeFsize(Fsize.value);
 89 }
 90 
 91 //document.oncontextmenu = new Function("return false;");
 92 //双击鼠标滚动屏幕的代码
 93 //var curPos, timer,speed=5;
 94 function initialize(){timer=setInterval ("scrollwindow()",300/speed);}
 95 function sc(){clearInterval(timer);}
 96 function scrollwindow(){
 97     curPos=document.body.scrollTop?document.body.scrollTop:document.documentElement.scrollTop;
 98     window.scroll(0,++curPos);
 99     var sTop=document.body.scrollTop?document.body.scrollTop:document.documentElement.scrollTop;
100     if (curPos !=sTop) sc();
101 }
102 function setSpeed(){
103 
104     speed = parseInt(scrollspeed.value);
105 
106 };
107 document.onmousedown = sc;
108 document.ondblclick = initialize;
109 loadSet();

 另外。xslt也使用到了css,这里提供css文件的源码

  1 .scroll{width:70px;float:right;
  2 position:fixed !important; top/**/:200px;
  3 position:absolute; z-index:100; top:expression(offsetParent.scrollTop+200);right:4px;}
  4 input{
  5 width:99%;
  6 border :1px solid #999999;
  7 font-weight:bold;
  8 background:transparent ;
  9 color:red;
 10 height:21px;
 11 font-size:10t;
 12 }
 13 body,b.rtop, b.rbottom,div.split{
 14 background: #4E3F3A;  /*url(back.gif);*/
 15 }
 16 div.roundconner,b.rtop b, b.rbottom b,div.Content,.NoPart{
 17 /*改变圆角矩形的背景色*/
 18 background:#FEF7DA;
 19 }
 20 *{
 21 font:             100.0% "宋体","Trebuchet MS", "Verdana", "Arial", "sans-serif";
 22 color:            #000000;
 23 }
 24 body {
 25 /*line-height : 180%;*/
 26 text-align:center;
 27 }
 28 div
 29 {
 30 /*firefox中,必须加入以下两句才能让div在body中居中显示*/
 31 margin-left:auto;
 32 margin-right:auto;
 33 }
 34 div.Content{
 35 line-height : 180%;
 36 font-size:14pt;
 37 }
 38 div.split{
 39 height:20px;
 40 }
 41 .title{
 42 color:white;
 43 font-size:16pt;
 44 }
 45 table{
 46 border-collapse:collapse ;
 47 }
 48 .roundconner {
 49 width:90%;
 50 text-align:left;
 51 
 52 }
 53 b.rtop, b.rbottom {
 54 display:    block;
 55 
 56 }
 57 b.rtop b, b.rbottom b {
 58 display:    block;
 59 height:     1px;
 60 overflow:   hidden;
 61 
 62 }
 63 b.r1 {
 64 margin: 0 5px;
 65 }
 66 b.r2 {
 67 margin: 0 3px;
 68 }
 69 b.r3 {
 70 margin: 0 2px;
 71 }
 72 b.rtop b.r4, b.rbottom b.r4 {
 73 margin: 0 1px;
 74 height: 2px;
 75 }
 76 a{
 77 text-decoration : none;
 78 }
 79 a:hover {
 80 color : red;
 81 }
 82 .imgDiv{
 83 text-align:center;
 84 width:98%;
 85 }
 86 th{
 87 background:transparent ;
 88 font-size:11pt;
 89 font-weight : normal;
 90 text-align : left;
 91 padding-left:8px;
 92 width:33%;
 93 }
 94 br{
 95 text-indent: 2em;
 96 }
 97 .Volume{
 98 font-weight:bold;
 99 font-size:9pt;
100 }
101 .PartIndex, .PartStep ,.PartStep a{
102 
103 background-color:#E8E2CC;
104 /*border :1px solid #CDCDDC;*/
105 font-size:10pt;
106 font-weight:bold;
107 height:21px;
108 vertical-align : center;
109 line-height:21px;
110 }
111 .PartIndex{
112 text-align : left;
113 float:left;
114 width:86%;
115 }
116 .PartStep{
117 text-align : right;
118 float:right;
119 width:14%;
120 }
121 .NoPart{
122 height:200px;
123 vertical-align : center;
124 line-height:200px;
125 font-size:36pt;
126 }

现在我们手头上有了如下文件

1.盘龙.xml         小说文件
2.Article.xslt     xml样式表文件
3.Article.xsd      xml的结构定义文件,对最终显示无影响
4.novel.js         读取和设置本机cookie,和提供自动滚屏功能
5.UI.css           

以上文件放置在同一个目录,双击盘龙.xml ,浏览器中就可以查看到小说内容

其实有了xml格式的章节内容,我们可以轻易的实现各种转化器,将xml格式转成txt,umd等等格式,并且可以以rss的形式发布小说内容。

这个留待以后在实现。

 

 

 

 

 

posted on 2012-11-28 13:57  simfe  阅读(1765)  评论(2编辑  收藏  举报