c - 如何从 xml schema(xsd) 的复杂类型获取正则表达式?

标签 c xml regex xsd

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

仅考虑复杂类型。例如:在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)” 结果是名称正则表达式。

另一个例子:(如果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>

表示复杂类型的名称是“request”。 。。。表示。。。的关系是“全部”(如果用&表示“全部”) 全部都是“&”,所以结果是“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);         

}

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

最佳答案

由于每个 XSD 内容模型实际上都可以通过 QName 转换为正则表达式,并且人们可能希望出于文档目的或为了更方便地推理复杂类型的目的而展示此 XSD,所以这个问题并不那么堂吉诃德式或者正如一些受访者似乎怀疑的那样,是偏离基地的。至少,不一定是堂吉诃德式的或大错特错的。

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

但是警告已经够多了。如果您确实想这样做,无论出于何种原因,该任务在概念上对于 XSLT 等合适的面向 XML 的语言来说都是微不足道的。我附加了一个 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}
  • 在任何两个同级表达式之间(即在每个具有右同级的表达式之后),发出适当的连接符:逗号、与号或或栏。

我希望这会有所帮助。

关于c - 如何从 xml schema(xsd) 的复杂类型获取正则表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12024826/

相关文章:

暴露给脚本系统的 C++ 函数 - 自描述参数类型

C程序从同一个文件中删除注释

c - 关于string和char的面试题

android - 具有矢量可绘制大小的 ImageView

regex - Perl 正则表达式中已弃用的左大括号 - 确切时间?

jquery - 寻找正则表达式仅替换三位数后的空格

.net - RegularExpressionValidator.ValidationExpression 强制长度为 10 或 12 个符号

c - 线程不作用于全局变量

C - 指向结构的指针到指针数组

xml - 从 XSLT 中删除属性并处理结果集