解析WordprocessingML(三)解析WordMl的基本方法和途径(b)-映射xsd

时间:2021-11-28 18:50:21

六、choicesequencemaxoccminocc的映射

简单的可以用List实现,复杂的必须自己写程序控制。

例子:CT_BodyEG_ContentBlockContent的映射方式,EG_ContentBlockContent包含了choicemaxocc

xsd:
解析WordprocessingML(三)解析WordMl的基本方法和途径(b)-映射xsd
1、               
精确映射,即实现一一映射。

下面的类实现Unbounded

    不足:调用者必须知道存在EG_ContentBlockContent组,而我希望所有组都对调用者透明。

public class U_EG_ContentBlockContent Content;

{

   public IList<EG_ContentBlockContent> Content;

}解析WordprocessingML(三)解析WordMl的基本方法和途径(b)-映射xsd

   下面的类实现 EG_ContentBlockContent
   
public   class  EG_ContentBlockContent: EG_RunLevelElts
    {
                     
        
#region  customXml

        
private  CT_CustomXmlBlock customXmlField;

        
///   <summary>
        
///  Block-Level Custom XML Element
        
///      - Required
        
///   </summary>
         public  CT_CustomXmlBlock customXml
        {
            
get  {  return  customXmlField; }
            
set  { customXmlField  =  value; }
        }

        
#endregion   //  customXml

        
#region  sdt

        
private  CT_SdtBlock sdtField;

        
///   <summary>
        
///  Block-Level Structured Document Tag
        
///      - Required
        
///   </summary>
         public  CT_SdtBlock sdt
        {
            
get  {  return  sdtField; }
            
set  { sdtField  =  value; }
        }
        
public  CT_P[] Paragraphs;
        
public  CT_Tbl[] Tbl;
        
#endregion   //  sdt
      
}

这种方式是最准确的映射,代价就是很难实现choice复杂,并且对调用者来说也不方便(这点可以用一个接口绕过,但是第一点确实很烦人)。

1、          不精确的xsd映射,xsd和类不存在一一对应关系。

仔细分析CT_Bodyxsd定义,根据定义xsd考虑所有可能产生的xml形式。让后用类包含所有形式。

       EG_ContentBlockContent包含四个元素和一个组,组可以用继承,四个元素中的两个也是unbounded,另外两个的maxocc1,由于EG_ContentBlockContent是作为unbounded引用的,所以四个元素实际上都是unbounded,他们在xml中可以以任意顺序出现n次。

       至此可以产生下面的映射方式:

public   class  EG_ContentBlockContent : EG_RunLevelElts
    {
        
#region  customXml

         
///   <summary>
        
///  Block-Level Custom XML Element
        
///      - Required
        
///   </summary>
         public  CT_CustomXmlBlock[] customXml
        {
            
get  {  // 类似p}
          
        }

        
#endregion   //  customXml


        
///   <summary>
        
///  Block-Level Structured Document Tag
        
///      - Required
        
///   </summary>
         public  CT_SdtBlock[] sdt
        {
            
get  {  // 类似p }
            
        }

        
#endregion   //  sdt

        
#region  Content

        
private  System.Collections.Generic.List < IContent >  content;

        
///   <summary>
        
///  The content of the body (to keep the order in the Paragraphs and Tables)
        
///   </summary>
         public  System.Collections.Generic.List < IContent >  Content
        {
            
get
            {
                
if  (content  ==   null )
                {
                    content 
=   new  System.Collections.Generic.List < IContent > ();
                }
                
return  content;
            }
        }

        
#endregion

        
#region  p

        
///   <summary>
        
///  Paragraphs
        
///      - Not required
        
///  To Add a Table use the Content Property
        
///   </summary>
         public  CT_P[] Paragraphs
        {
            
get
            {
                
if  (content  ==   null )
                {
                    
return   new  CT_P[ 0 ];
                }
                
else
                {
                    System.Collections.Generic.List
< CT_P >  list  =   new  System.Collections.Generic.List < CT_P > ();
                    
foreach  (IContent elts  in  content)
                    {
                        
if  (elts  is  CT_P)
                        {
                            list.Add((CT_P)elts);
                        }
                    }
                    
return  list.ToArray();
                }
            }
        }

        
#endregion   //  p

        
#region  tbl


        
///   <summary>
        
///  Table
        
///      - Not required
        
///  To Add a Table use the Content Property
        
///   </summary>
         public  CT_Tbl[] tbl
        {
            
get
            {
                
if  (content  ==   null )
                {
                    
return   new  CT_Tbl[ 0 ];
                }
                
else
                {
                    System.Collections.Generic.List
< CT_Tbl >  list  =   new  System.Collections.Generic.List < CT_Tbl > ();
                    
foreach  (IContent elts  in  content)
                    {
                        
if  (elts  is  CT_Tbl)
                        {
                            list.Add((CT_Tbl)elts);
                        }
                    }
                    
return  list.ToArray();
                }

            }
        }
}

这要求所有的组成员必须实现某个接口,在此用了IContent。这样定义Group,从本质上看已经不是xsdgroup了。在这个元素中这样处理简单,但是在别的元素中就不一定,它增加了问题的不确定性,或许后面都可以这样映射,也可能回出现大问题,不得不采用第一种方式,这样就又会把结构打乱,问题会变得更复杂,这也是为啥要尽可能的把类和xsd一一对应,如此一来,结构上有ms设计的xsd做参考,一切的变化都不会太离谱,ms改变xsd后,类库修改也小些。

3、最后看看WarstarDev.Office2k7的映射方式(错误的):

public   class  EG_ContentBlockContent : EG_RunLevelElts
    {
        
#region  customXml

        
private  CT_CustomXmlBlock customXmlField;

        
///   <summary>
        
///  Block-Level Custom XML Element
        
///      - Required
        
///   </summary>
         public  CT_CustomXmlBlock customXml
        {
            
get  {  return  customXmlField; }
            
set  { customXmlField  =  value; }
        }

        
#endregion   //  customXml

        
#region  sdt

        
private  CT_SdtBlock sdtField;

        
///   <summary>
        
///  Block-Level Structured Document Tag
        
///      - Required
        
///   </summary>
         public  CT_SdtBlock sdt
        {
            
get  {  return  sdtField; }
            
set  { sdtField  =  value; }
        }

        
#endregion   //  sdt

        
#region  Content

        
private  System.Collections.Generic.List < EG_RunLevelElts >  content;

        
///   <summary>
        
///  The content of the body (to keep the order in the Paragraphs and Tables)
        
///   </summary>
         public  System.Collections.Generic.List < EG_RunLevelElts >  Content
        {
            
get
            {
                
if  (content  ==   null )
                {
                    content 
=   new  System.Collections.Generic.List < EG_RunLevelElts > ();
                }
                
return  content;
            }
        }

        
#endregion

        
#region  p

        
///   <summary>
        
///  Paragraphs
        
///      - Not required
        
///  To Add a Table use the Content Property
        
///   </summary>
         public  CT_P[] Paragraphs
        {
            
get
            {
                
if  (content  ==   null )
                {
                    
return   new  CT_P[ 0 ];
                }
                
else
                {
                    System.Collections.Generic.List
< CT_P >  list  =   new  System.Collections.Generic.List < CT_P > ();
                    
foreach  (EG_RunLevelElts elts  in  content)
                    {
                        
if  (elts  is  CT_P)
                        {
                            list.Add((CT_P) elts);
                        }
                    }
                    
return  list.ToArray();
                }
            }
        }

        
#endregion   //  p

        
#region  tbl

    
        
///   <summary>
        
///  Table
        
///      - Not required
        
///  To Add a Table use the Content Property
        
///   </summary>
         public  CT_Tbl[] tbl
        {
            
get
            {
                
if  (content  ==   null )
                {
                    
return   new  CT_Tbl[ 0 ];
                }
                
else
                {
                    System.Collections.Generic.List
< CT_Tbl >  list  =   new  System.Collections.Generic.List < CT_Tbl > ();
                    
foreach  (EG_RunLevelElts elts  in  content)
                    {
                        
if  (elts  is  CT_Tbl)
                        {
                            list.Add((CT_Tbl) elts);
                        }
                    }
                    
return  list.ToArray();
                }
              
            }
        }

        
#endregion   //  tbl
}

错误的地方是,它把我上面说的两种方式和在了一起(更像第二种),造成CT_CustomXmlBlockCT_SdtBlock没有实现unbounded,是个四不像的映射方式。其次他借用EG_RunLevelElts来管理Ilist元素,有点太取巧了(感觉不会是MS为程序映射xsd而故意设计的,但是整个EG_ContentBlockContent的元素都实现了EG_RunLevelElts,实在是巧合!!),在此可能简单写,但是对程序结构并没有好处。

两种方式各有优缺点,半斤八两,真不知道用哪种方式好些,第一种方式choice很难处理,我想到的只有在运行时做检测一种办法,希望有人能提出更好的解决方案。

第二种把choice绕过去了,但是他并不是xsd到类的一一映射,风险很大,很可能是灾难性的。

现在我采用的是另一种方式,但现在已经走到死路了,逻辑变的越来越复杂,必须改成这两种之一。目前比较倾向于第二种,第一种方式对调用者来说,把检测推到运行时几乎是不能忍受的,但又担心第二种会出现我现在碰到的情况,最终复杂到没有办法处理。

七、sequencechoice类似,就不说了。其他问题就是由于.net不支持多继承导致的,解决方式只能是在映射时做些调整,又是一个必须要仔细权衡的问题,弄不好也会把结构弄的特别乱。

总,想写一个最好的WordMl库,目前还赶不上WarstarDev.Office2k7,但是它用反射、XmlWriter解析的方式已经决定它的灵活性和功能都是有限的,再加上它在映射xsd方面的错误、它的结构也不太好,总会超过它的。

      WordMl实在是个超级复杂的东西,尤其是采用Dom解析方式时,我做到现在结构已经大调两次了,但是还必须再做一次大的调整才可能把结构稳定下来,到今天才算把wordml的结构弄清楚,入门了,希望这次调整是最后一次,两个月下来快被它弄死了。
   

解析WordprocessingML(一)查找和替换

http://www.cnblogs.com/bluewater/admin/EditPosts.aspx?postid=627710

解析WordprocessingML(二)通过数据集自动生成表格

http://www.cnblogs.com/bluewater/archive/2007/03/02/662040.html

解析WordprocessingML(三)解析WordMl的基本方法和途径(a

http://www.cnblogs.com/bluewater/archive/2007/03/02/661824.html

解析WordprocessingML(三)解析WordMl的基本方法和途径(b

http://www.cnblogs.com/bluewater/archive/2007/03/02/661885.html

解析WordprocessingML(四)转换到Html格式

Xsd入门

http://www.cnblogs.com/bluewater/archive/2007/03/02/661927.html