-2

如何从 xml 模式中获取常规 exp?我们知道 xml 模式有明确的正则表达式。但是如何实现呢?(例如,编写一个程序来获得常规的 exp)。

只考虑 complexType。例如:在 xsd 中,我们有:

<xs:element name="letter">
  <xs:complexType mixed="true">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="orderid" type="xs:positiveInteger"/>
      <xs:element name="shipdate" type="xs:date"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

或者:

<xs:complexType name="lettertype" mixed="true">
  <xs:sequence>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="orderid" type="xs:positiveInteger"/>
    <xs:element name="shipdate" type="xs:date"/>
  </xs:sequence>
</xs:complexType>

查找序列的意思是“,”,所以结果是“letter (name,orderid,shipdate)” 结果是name regex。

另一个例子:(如果 xsd 有这个:)

<xs:complexType name="request">
<xs:all>
  <xs:element name="url" type="xs:string"/>
  <xs:element name="component" type="xs:string"/>
  <xs:element name="action" type="xs:string" minOccurs="0"/>
  <xs:element name="params" type="varList" minOccurs="0"/>
  <xs:element name="session" type="varList" minOccurs="0"/>
  <xs:element name="cgi-data" type="varList" minOccurs="0"/>
</xs:all>

表示 complexType 的名称是“request”。。。。表示。。。的关系是“all”(如果我们用&表示“all”) all是“&”,所以结果是“request url&component&action¶ms&session&cgi-data”

有没有人可以帮我编写一个程序来实现这个功能?或者告诉我一个算法?

我编写了一个程序,但它太错误了,而且逻辑错误。这是我的程序:

#include<stdio.h> 
#include<string.h>
#include <stdlib.h>
#include<io.h> 
#define MatchMaxLen 69500
void process(char *result,char *str,char *str2,FILE* fp1)
{
if(strstr(str2,"complexType>")) fgets(str2,3000,fp1);
        //strcat(str,   str2);
    char c[5],*pem;
    int m=0;   if(!strstr(str2,"xs:sequence")&&!strstr(str2,"xs:choice")&&!strstr(str2,"xs:all")) return;
    if(strstr(str,"element name=\""))
        {
            pem=strstr(str,"element name=\"")+strlen("element name=\"");

            while(*pem!='\"')*result++=*pem++;//put element name in purec

            *result++=' ';
        }   
    if(strstr(str2,"xs:sequence")) {*result++='(';c[m++]=',';}
    if(strstr(str2,"xs:choice")) {*result++='(';c[m++]='|';}
    if(strstr(str2,"all")) {*result++='(';c[m++]='&';}
    fgets(str2,3000,fp1);
    while(!(strstr(str2,"sequence>")||strstr(str2,"choice>")||strstr(str2,"all>")))
        {
            if(str2,"complexType>") process(result,str,str2,fp1);
    if(strstr(str2,"element name=\""))
    {
    pem=strstr(str2,"element name=\"");
    pem=pem+strlen("element name=\"");
    }
    if(strstr(str2,"element ref=\""))
    {
    pem=strstr(str2,"element ref=\"");
    pem=pem+strlen("element ref=\"");
    }
    while(*pem!='\"') *result++=*pem++;

    char *pmax,*pmin;
    pmin=strstr(str2,"minOccurs=\"");
    pmin=pmin+strlen("minOccurs=\"");
    pmax=strstr(str2,"maxOccurs=\"");
    pmax=pmax+strlen("maxOccurs=\"");
    if(strstr(str2,"minOccurs")&&strstr(str2,"maxOccurs"))
    {
        if(*pmax=='1'&&*pmin=='0')
        {
        *result++=')';
        *result++='?';
        }
    if(*pmax=='u'&&*pmin=='0')
        {   
        *result++=')';
        *result++='*';
        }
    if(*pmax=='u' && *pmin=='1')
        {
        *result++=')';
        *result++='+';
        }
    *result++=c[m-1];
    }

    fgets(str2,3000,fp1);}
    m--;
}

void main()
{
char type[100][20];
char name[100][20];
char res[3000];
char *result=res;
int flag=0;
char *str, *str2,*psp;
char destfname[20];
char *path="E:\\study\\research\\summer\\program\\*.xsd";/*use this when needed in future extension.Well, been used currently*/
char path1[]="E:\\study\\research\\summer\\program\\";
int len;
FILE *fp1,*fp2; 
char string[MatchMaxLen];
char string2[3000];
struct _finddata_t   ffblk;
long done= _findfirst(path,&ffblk);  
do{ /*sprintf(filename,"dtd%d.dtd",i); 
In the future if the filename is not regular or we don't know the exact numbersome day, 
you may need function like _findnext,_findfirst.Well, currently being used*/
strcat(path1,ffblk.name);
if ((fp1=fopen(path1,"r"))==NULL)
{ /* read source file*/
        printf("cannot open file\n");
        exit(0);
}
sprintf(destfname,"IncludeNamexsdRe%s.txt",ffblk.name);
if((fp2=fopen(destfname,"w"))==NULL)
{ /* destination file*/
        printf("cannot open file\n"); 
        exit(0);
}   
char *pem;
int j(0);
int i(0);
while (fgets(string,MatchMaxLen,fp1))
{//first while's purpose is to create the map of name and type      
str=string;
if(!strstr(str,"element name")) continue;// the thing u need to process
i++;
pem=strstr(str,"element name");
pem=pem+strlen("element name=")+1;//pem: pointer of the element name
while(*pem!='\"')//while not the end point """
{
name[i][j++]=*pem++;//put the element name to the name[][]
}
name[i][j]='\0';
if(!(psp=strstr(string,"type="))) continue;
memccpy(type[i],psp+6,'\"',22); 
}
rewind(fp1);//normal process, here we go
char purecomplex[20];
char *purec=purecomplex;
char ctype[20];
char *cotype=ctype;
while (fgets(string,MatchMaxLen,fp1))
{   
        if( strlen( string ) == 0 ) 
            continue;
    str=string;
    if (str == NULL) 
        continue; 
    if( strlen( string ) == 1 ) continue;   
    //printf("%s",string);

    str2=string2;
    if(strstr(str,"<!--")) 
    {
        while(!strstr(str,"-->"))
        {
        fgets(str2,3000,fp1);
        strcat(str, str2);
    //delete useless char
    //printf("%s\n",str2); 
        }
    continue;
    }
    if(!(pem=strstr(str,"element name=\""))&&!strstr(str,"complexType name=")) continue;

    /*while(match(str))
    {*/
        fgets(str2,3000,fp1);
        if(strstr(str2,"annotation>"))
        {
            do{ fgets(str2,3000,fp1);}while(!strstr(str2,"</xs:annotation>"));
            fgets(str2,3000,fp1);
        }

        if(strstr(str,"complexType name=\""))
        {
            char* pt;
            pt=strstr(str,"complexType name=\"")+strlen("complexType name=\"");
    //if(strstr(str,"element name=\"")) pt=strstr(str,"element name=\"")+strlen("element name=\"");

            while(*pt!='"') *result++=*pt++;//if has complextype name, put it in cotype

            *result++=' ';
        }
        process(result,str,str2,fp1);
    }//}
    *result='\0';
    fputs(res,fp2 );
    //fputc('\n',fp2 );

    //printf("%s\n",ffblk.name);
    printf("2===%s\n",string);
    fclose(fp1);
    fclose(fp2);
}while(!_findnext(done,&ffblk));

_findclose(done);         

}

有没有人可以帮我编写一个程序来实现这个功能?或者告诉我一个算法?

4

1 回答 1

1

由于实际上每个 XSD 内容模型都可以转换为 QNames 上的正则表达式,并且出于文档目的或更方便地推理复杂类型的目的,人们可能希望展示此 XSD,因此这个问题并不像堂吉诃德式或离题。一些受访者似乎倾向于怀疑。至少,不一定是堂吉诃德式的或离谱的。

但是,如果您提供更多关于您为什么要这样做以及您希望对结果做什么的背景知识,那么热情地帮助您解决这个问题会更容易。如果您想根据模式验证文档,那么通常最好使用现成的验证器。(编写自己的验证器而不是使用现成的工具总是很有趣,但是任何能够编写自己的 XSD 验证器的人都不需要帮助将 XSD 内容模型转换为类似正则表达式的符号,所以我推断那不是您的目标。)

但是足够的警告。如果您真的想这样做,无论出于何种原因,使用合适的面向 XML 的语言(如 XSLT),该任务在概念上是微不足道的。我附加了一个 XSLT 程序来说明一般方法;它在简单的情况下可以正常工作(据我测试过),但它忽略了使用真实模式所需的所有簿记和繁琐的细节。它不尝试处理复杂类型扩展、多命名空间模式文档或为另一个复杂类型本地元素定义的复杂类型。和您的示例一样,它从被翻译的复杂类型或封闭元素声明中获取命名正则表达式的名称,这意味着如果模式具有具有相同本地名称的类型和元素,它将遇到麻烦。

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                >

  <xsl:output method="text"/>

  <!--* Ignore anything that looks complicated *-->
  <xsl:template match="xsd:attribute 
                       | xsd:attributeGroup
                       | xsd:group
                       | xsd:schema/xsd:element[@type]
                       | xsd:notation
                       | xsd:annotation
                       "/>

  <!--* Ignore text nodes (otherwise the output will be
      * inundated with whitespace) *-->
  <xsl:template match="text()"/>

  <!--* Top-level elements with local complex types; those
      * we want to handle.
      *-->
  <xsl:template match = "xsd:schema/xsd:element[xsd:complexType]">
    <xsl:apply-templates/>
  </xsl:template>

  <!--* Aha!  A complex type whose content model we want to turn 
      * into a regular expression 
      *-->
  <xsl:template match = "xsd:element/xsd:complexType
                         [xsd:sequence | xsd:choice | xsd:all]">
    <!--* write out the name for the named regex *-->
    <xsl:value-of select="concat('&#xA;&#xA;',
                          @name, parent::xsd:element/@name, 
                          ' ')"/>
    <!--* write out the regex *-->
    <xsl:apply-templates/>
  </xsl:template>

  <!--* Simple recursive case:  we encounter a model group. *-->
  <xsl:template match = "xsd:sequence|xsd:choice|xsd:all">
    <!--* Parenthesize the group and handle its children. *-->
    <xsl:text>(</xsl:text>
    <xsl:apply-templates/>
    <xsl:text>)</xsl:text>

    <!--* Append *, ?, +, or {min, max}. *-->
    <xsl:call-template name="occurrence-indicator"/>

    <!--* If our parent has further children, 
        * append the appropriate connector. *-->
    <xsl:call-template name="connector"/>
  </xsl:template>

  <!--* An element in a content model. *-->
  <xsl:template match = "xsd:element[ancestor::xsd:complexType]">
    <!--* Write out the element's name.  We're lazy so 
        * we don't bother with a QName for a local element.
        * Also, we don't recur. *-->
    <xsl:value-of select="concat(@ref, @name)"/>

    <!--* Handle occurrence indicator and connect
        * just as for groups. *-->
    <xsl:call-template name="occurrence-indicator"/>
    <xsl:call-template name="connector"/>
  </xsl:template>


  <!--* Emit the appropriate occurrence indicator for
      * a group or element.
      * Use {min,max}, {min,}, or {n} notation for 
      * non-standard occurrence counts.
      *-->
  <xsl:template name="occurrence-indicator">
    <xsl:choose>
      <xsl:when test="(@minOccurs='1' or not(@minOccurs)) 
                      and 
                      (@maxOccurs='1' or not(@maxOccurs))">
        <xsl:text></xsl:text>
      </xsl:when>
      <xsl:when test="@minOccurs='0' 
                      and 
                      (@maxOccurs='1' or not(@maxOccurs))">
        <xsl:text>?</xsl:text>
      </xsl:when>
      <xsl:when test="@minOccurs='0' and @maxOccurs='unbounded'">
        <xsl:text>*</xsl:text>
      </xsl:when>
      <xsl:when test="(@minOccurs='1' or not(@minOccurs)) 
                      and 
                      @maxOccurs='unbounded'">
        <xsl:text>+</xsl:text>
      </xsl:when>
      <xsl:when test="@minOccurs=@maxOccurs">
        <xsl:value-of select="concat('{', @minOccurs,'}')"/>
      </xsl:when>
      <xsl:when test="@maxOccurs='unbounded'">
        <xsl:value-of select="concat('{', @minOccurs,',}')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat('{', 
                              @minOccurs,
                              ',',
                              @maxOccurs,
                              '}')"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="connector">
    <!--* Emit the appropriate connector, if we need one. *-->
    <xsl:if test="following-sibling::*[self::xsd:sequence 
                  | self::xsd:choice 
                  | self::xsd:all 
                  | self::xsd:element]">
      <xsl:choose>
        <xsl:when test="parent::xsd:sequence">
          <xsl:text>, </xsl:text>
        </xsl:when>
        <xsl:when test="parent::xsd:choice">
          <xsl:text> | </xsl:text>
        </xsl:when>
        <xsl:when test="parent::xsd:all">
          <xsl:text> &amp; </xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

如果由于某种原因您不能或不会处理 XSLT 中的问题,那么您必须记住的是,您只需要对树进行正常的深度优先遍历(特别是模式文档规范中的 XML 树)内容模型),在适当的时间发出适当的括号和运算符。

  • 在每个元素上,发出适当的 QName。
  • 在每个组上,发出一个左括号,处理孩子,然后发出一个右括号。
  • 在每个表达式(无论是元素还是组)之后,发出一个出现指示符:*、+、?、空字符串或计数运算符,如{4}{2,}{0,4}
  • 在任何两个兄弟表达式之间(即在每个具有右兄弟的表达式之后),发出一个适当的连接符:逗号、与号或或-bar。

我希望这有帮助。

于 2012-08-19T19:20:50.187 回答