Giter VIP home page Giter VIP logo

xsd-parser-rs's Introduction

xsd-parser-rs

An xsd/wsdl => rust code generator written in rust. The main target is for generation of the ONVIF Specifications but should work for other SOAP/XSDL/WSDL needs.

Work in Progress

This is still a work in progress. So please feel free to open issues and submit PRs. Please be sure to read and follow our Code of Conduct.

XSD types mapping

A following mapping used to represent built-in XSD types as rust types:

XSD rust
hexBinary String
base64Binary String
boolean bool
integer Integer (1)
nonNegativeInteger NonNegativeInteger (1)
positiveInteger PositiveInteger (1)
nonPositiveInteger NonPositiveInteger (1)
negativeInteger NegativeInteger (1)
long i64
int i32
short i16
byte i8
unsignedLong u64
unsignedInt u32
unsignedShort u16
unsignedByte u8
decimal Decimal (2)
double f64
float f64
date Date (3)
time Time (3)
dateTime DateTime (3)
dateTimeStamp DateTimeStamp (3)
duration Duration (4)
gDay GDay (5)
gMonth GMonth (5)
gMonthDay GMonthDay (5)
gYear GYear (5)
gYearMonth GYearMonth (5)
string String
normalizedString String
token String
language String
Name String
NCName String
ENTITY String
ID String
IDREF String
NMTOKEN String
anyURI String
QName String
NOTATION String
ENTITIES Vec<String>
IDREFS Vec<String>
NMTOKENS Vec<String>

Notes:

(1) we are using our own big integer types, that wrap num_bigint::BigInt and num_bigint::BigUint and provide XML (de)serialization with yaserde. You can find Integer, NonNegativeInteger, PositiveInteger, NonPositiveInteger and NegativeInteger in the corresponding files within xsd-types/src/types/

(2) we are using our own type Decimal, which wraps bigdecimal::BigDecimal and provides XML (de)serialization with yaserde. You can find Decimal in xsd-types/src/types/decimal.rs

(3) we are using our own time types, that wrap types from chrono crate and provide XML (de)serialization with yaserde. You can find Date, Time, DateTime and DateTimeStamp in the corresponding files within xsd-types/src/types/. Since chrono has it flaws and does not follow ISO 8601 strictly, we use self-implemented parsing and might replace chrono in the future. Feel free to suggest an appropriate crate for time handling.

(4) we are using our own type Duration, since there is no known implementation in rust that supports proper month/years holding and literal representation. You can find Duration in xsd-types/src/types/duration.rs

(5) we are using our own gregorian calendar types, that provide XML (de)serialization with yaserde following ISO 8601 strictly. You can find gDay, gMonth, gMonthDay, gYear and gYearMonth in the corresponding files within xsd-types/src/types/.

any elements handling

There are cases when schema allows extensions for the certain type.

<xs:complexType name="MyType">
    <xs:sequence>
        <xs:element name="Parameters" type="xs:string" />
        <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:anyAttribute namespace="##any" processContents="lax"/>
</xs:complexType>

In such cases we don't know in advance what fields must be present in Rust struct so we don't add them to output:

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "tns", namespace = "tns: http://example.com")]
pub struct MyType {
    #[yaserde(prefix = "tns", rename = "Parameters")]
    pub parameters: String,
}

In this unlucky situation to support extensions user can either:

  • modify the generated code and add extension fields manually
  • modify source XSD and add extension elements there

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

xsd-parser-rs's People

Contributors

dmitrysamoylov avatar drchat avatar fabriceds avatar jplatte avatar leonidkrutovsky avatar lkirkwood avatar roastveg avatar smw-wagnerma avatar sovictor avatar victor-soloviev avatar whynothugo avatar zeenix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xsd-parser-rs's Issues

Implement folder-to-folder processing

XSD files are highly interconnected, so we typically want to process not one file, but the whole set of files forming the dependency graph. To achieve that, we have to have mode, in which XSD-parser takes a folder full of XSD files as an input and generates a folder with rust files. In the scope of this issue, it is okay to process files independently for now.

Support attributes in a schema root

xs:schema may have attributes within itself.

xmlmime.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
          xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
          targetNamespace="http://www.w3.org/2005/05/xmlmime" >

 <xs:attribute name="contentType">
   <xs:simpleType>
     <xs:restriction base="xs:string" >
     <xs:minLength value="3" />
     </xs:restriction>
   </xs:simpleType>
 </xs:attribute>

 ...

</xs:schema>

Current state of generated code for this case:

//generated file
  #[yaserde(attribute, rename = "contentType")]
  pub content_type: Option<String>,
  #[yaserde(attribute, rename = "expectedContentTypes")]
  pub expected_content_types: Option<String>,
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "xmime", namespace = "xmime: http://www.w3.org/2005/05/xmlmime")]
pub struct Base64Binary {
  #[yaserde(attribute, prefix = "xmime" rename = "contentType")]
  pub xmime_content_type: Option<ContentType>,
}


#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "xmime", namespace = "xmime: http://www.w3.org/2005/05/xmlmime")]
pub struct HexBinary {
  #[yaserde(attribute, prefix = "xmime" rename = "contentType")]
  pub xmime_content_type: Option<ContentType>,
}

Find a way to serialize tuple structs with yaserde

For following xsd

<xs:simpleType name="Name">
  <xs:restriction base="xs:string">
    <xs:maxLength value="64"/>
  </xs:restriction>
</xs:simpleType>

we are generating following struct

#[derive(Default, PartialEq, Debug)]
pub struct Name (String);

Turns out that YaSerialize could not be derived for structs with nameless fields (tupple structs), nor it could be used for structs containing such tupple structs.

We need to implement YaSerialize and YaDeserialize traits for structs with nameless fields.

Associated issue in yaserde repo: media-io/yaserde#25

How to use the project?

Hey guys.

I was able to generate the rust code for my xsd, but I'm having a hard time compiling, I have the following problem with the YaSerialize/YaDeserialize derive:

no method named `serialize` found for struct `std::string::String` in the current scope

method not found in `std::string::String`rustc(E0599)

For the following code:

use yaserde_derive::{YaDeserialize, YaSerialize};

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde()]
pub struct Header {
    #[yaserde(rename = "merchantId")]
    pub merchant_id: MerchantId,

    #[yaserde(rename = "merchantName")]
    pub merchant_name: MerchantName,

    #[yaserde(rename = "createdOn")]
    pub created_on: CreatedOn,
}

I guess I'm missing some import, but can't figure it out which.

Support for restriction emumerations

<xs:simpleType name="PropertyOperation">
  <xs:restriction base="xs:string">
    <xs:enumeration value="Initialized"/>
    <xs:enumeration value="Deleted"/>
    <xs:enumeration value="Changed"/>
  </xs:restriction>
</xs:simpleType>

Support for nested sequence fields?

Hi sorry for the bother.

I'm facing the following error while trying to generate Rust's structs for the following xsd input.txt (I've changed to extension to .txt to be able to upload the file)

thread 'main' panicked at 'internal error: entered unreachable code:
Error: Element { tag_name: {http://www.w3.org/2001/XMLSchema}sequence, attributes: [Attribute { name: minOccurs, value: "0" }, Attribute { name: maxOccurs, value: "11" }], namespaces: [Namespace { name: Some("xs"), uri: "http://www.w3.org/2001/XMLSchema" }] }
Struct(Struct { name: "Foo", comment: None, fields: RefCell { value: [StructField { name: "Bazs", type_name: "BazsType", comment: None, subtypes: [Struct(Struct { name: "BazsType", comment: None, fields: RefCell { value: [StructField { name: "initialsBaz", type_name: "initialsBazType", comment: None, subtypes: [Enum(Enum { name: "initialsBazType", cases: [EnumCase { name: "Fizz01", comment: None, value: "Fizz01", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz02", comment: None, value: "Fizz02", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz03", comment: None, value: "Fizz03", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz04", comment: None, value: "Fizz04", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz05", comment: None, value: "Fizz05", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz06", comment: None, value: "Fizz06", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz07", comment: None, value: "Fizz07", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz08", comment: None, value: "Fizz08", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz09", comment: None, value: "Fizz09", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz10", comment: None, value: "Fizz10", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz11", comment: None, value: "Fizz11", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz12", comment: None, value: "Fizz12", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz13", comment: None, value: "Fizz13", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz14", comment: None, value: "Fizz14", type_name: None, type_modifiers: [], source: Restriction }, EnumCase { name: "Fizz15", comment: None, value: "Fizz15", type_name: None, type_modifiers: [], source: Restriction }], comment: None, type_name: "xs:string", subtypes: [], source: Restriction })], source: Element, type_modifiers: [None] }] }, subtypes: [] })], source: Element, type_modifiers: [None] }] }, subtypes: [] })', xsd-parser/src/parser/sequence.rs:38:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

By looking at the code it seems that the problem may lie in the presence of nested sequence fields in the xsd input file.

I tried to look inside both the code base and the test suite but I didn't find anything useful to endorse my guess ๐Ÿ˜ž

Obviously do not hesitate to ask for any kind of additional info I may have missed to specify.

Add choice element support for complex type

<xs:complexType name="ColorOptions">
	<xs:annotation>
		<xs:documentation>
			Describe the colors supported. Either list each color or define the range of color values.
		</xs:documentation>
	</xs:annotation>
	<xs:choice>
		<xs:element name="ColorList" type="tt:Color" maxOccurs="unbounded">
			<xs:annotation>
				<xs:documentation>List the supported color.</xs:documentation>
			</xs:annotation>
		</xs:element>
		<xs:element name="ColorspaceRange" type="tt:ColorspaceRange" maxOccurs="unbounded">
			<xs:annotation>
				<xs:documentation>Define the range of color supported.</xs:documentation>
			</xs:annotation>
		</xs:element>
	</xs:choice>
	<xs:anyAttribute processContents="lax"/>
</xs:complexType>

https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms256109(v=vs.100)

Add maxOccurs and minOccurs logic for nested elements

<xs:sequence>
	<xs:element name="Color" type="tt:ColorOptions" minOccurs="0">
		...
	</xs:element>
	<xs:element name="Transparent" type="tt:IntRange" minOccurs="0">
		...
	</xs:element>
	<xs:element name="Extension" type="tt:OSDColorOptionsExtension" minOccurs="0"/>
</xs:sequence>

minOccurs = 0 => Optional;
minOccurs > 1 || maxOccurs > 1 => Vec;
maxOccurs = 1 || minOccurs = 1 => Type;

Implement xs:union support

From b-2.xsd:

<xsd:simpleType name="AbsoluteOrRelativeTimeType">
 <xsd:union memberTypes="xsd:dateTime xsd:duration" />
</xsd:simpleType>

Current version of parser/generator does not support unions.

Struct generated from simpleContent with extention lacks field generated from base

From

<xs:complexType name="reasontext">
    <xs:simpleContent>
    <xs:extension base="xs:string">
      <xs:attribute ref="xml:lang" use="required"/>
    </xs:extension>
  </xs:simpleContent>
  </xs:complexType>

we generate

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(
    prefix = "tns",
    namespace = "tns: http://www.w3.org/2003/05/soap-envelope"
)]
pub struct Reasontext {
    #[yaserde(attribute, prefix = "xml" rename = "lang")]
    pub lang: String,
}

which, obviously, lacks another String field that represents reason itself

Non-ONVIF: Implement facet "fixed"

This page shows an example of fixed usage: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms256061(v=vs.100)

fixed is not currently supported by the parser, due to ints absence in XSD files of ONVIF.

To implement fixed support:

  • go to xsd-parser-rs/parser/xsd_element.rs and add facet "Fixed" into enum FacetType;
  • go throug usages of FacetType::MaxInclusive to get idea of places where facets are processed in the code of the project;
  • implement validation for Fixed similar to the way validation for MaxInclusive implemented.

Add yaserde attributes for elements in sequence

Now we only have the generation for attributes. We need to add the same for the elements.

<xs:complexType name="Config">
	<xs:sequence>
		<xs:element name="Parameters" type="tt:ItemList">
...
		</xs:element>
	</xs:sequence>
	<xs:attribute name="Name" type="xs:string" use="required">	
...	
	</xs:attribute>
	<xs:attribute name="Type" type="xs:QName" use="required">
...
	</xs:attribute>
</xs:complexType>

result code:

pub struct Config {
  #[yaserde(attribute, rename = "Parameters")]
             ^^^^^^^^ this place
  pub parameters: ItemList,  // ...

  #[yaserde(attribute, rename = "Name")]
  pub name: String, //...

  #[yaserde(attribute, rename = "Type")]
  pub type: xs::QName,  //...
} 

Layered parsing/generating pipeline

To effectively resolve the following issues:

and to achieve better decomposition and extensibility, we are implementing a new approach, in which the parsing/generation pipeline deals with four levels of data representation:

  • raw XML data;
  • XSD models;
  • abstract code;
  • generated code in rust.

Thus, four conversions are occuring in the process:

  • parsing raw text to XML Tree [We are using lib roxmltree. It`s fast and simple. However, this part is made replaceable];
  • parsing XML data to XSD models;
  • building an abstract code model based on XSD model;
  • generating rust code;

Levels are well-isolated, meaning that structs from the current level know only about structs from one previous level. During each conversion, only two levels of abstraction are involved. Each level and transformer are customizable, meaning that the processing of vendor-specific elements might be easily implemented.

The main differences between the master branch and the new approach are:

  • separation of XSD model layer and abstract code layer, which were mixed in master;
  • resolving of dependencies/imports during abstract code model building.

Code generating is well-implemented in master and should change only slightly, while real changes coming to prior stages.

Here is the list of subtasks:

  • Implement XML->XSD convertion for all XSD types from standard;
    • Integrate our custom XSD types from xsd-types;
    • Implement holders for the rest of XSD types presented in ONVIF;
    • Implement type resolver class to process imports and dependencies;
    • (non-ONVIF) Implement holders for XSD types not presented in ONVIF;
  • Implement XSD -> abstract code convertion for all types;
    • Implement abstract code holders and type conversions for them (see #98);
    • Implement dependency processing with XSD type resolver;
  • Tweak code generation to generate from abstract code structs rather then structs in master branch.

Empty enum case

pub enum EnumCaseType {
   ,
   __Unknown__(String),
}
 <xs:union memberTypes="xs:language">
    <xs:simpleType>
     <xs:restriction base="xs:string">
      <xs:enumeration value=""/>
     </xs:restriction>
    </xs:simpleType>
   </xs:union>

Add xsd generation to wsdl generator

In WSDL files have sections 'types' [0..*] in which the 'xsd:schema' items are located.

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" targetNamespace="http://www.onvif.org/ver10/device/wsdl">
  <wsdl:types>
    <xs:schema targetNamespace="http://www.onvif.org/ver10/device/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" elementFormDefault="qualified" version="18.12">
      <xs:import namespace="http://www.onvif.org/ver10/schema" schemaLocation="../../../ver10/schema/onvif.xsd"/>
      <xs:element name="GetServices">
....
  </wsdl:types>

We have a ready-made xsd-parser with function

pub fn parse_schema<'input>(schema: &Node<'_, 'input>) -> RsFile<'input>

And we have rust code generator for xsd with

pub fn generate_rs_file(&self, schema: &RsFile<'input>) -> String

In WSDL parser we have 'Definitions' struct with method

pub fn types(&self) -> &[Types]

and 'Types' struct with method

pub fn schemas(&self) -> Vec<Node<'_, '_>>'

You need to think of an aggregating level for two parsers and two generators with a convenient API for the end user.

Anonymous types clash

Consider this schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:tns="http://example.com"
           targetNamespace="http://example.com"
           elementFormDefault="qualified">

    <xs:complexType name="FooType">
        <xs:sequence>
            <xs:element name="Extension">
                <xs:complexType/>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="BarType">
        <xs:sequence>
            <xs:element name="Extension">
                <xs:complexType/>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="Foo" type="tns:FooType"/>
</xs:schema>

Currently Extension type is generated twice. What if we put it under a separate module:

pub mod foo_type {
    use super::*;

    #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
    #[yaserde(prefix = "tns", namespace = "tns: http://example.com")]
    pub struct Extension {}
}

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "tns", namespace = "tns: http://example.com")]
pub struct FooType {
    #[yaserde(prefix = "tns", rename = "Min")]
    pub extension: foo_type::Extension,
}

pub mod bar_type {
    use super::*;

    #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
    #[yaserde(prefix = "tns", namespace = "tns: http://example.com")]
    pub struct Extension {}
}

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "tns", namespace = "tns: http://example.com")]
pub struct BarType {
    #[yaserde(prefix = "tns", rename = "Min")]
    pub extension: bar_type::Extension,
}

Compiler error in generated validation

In generated file xsd/types.rs

// Type used to represent the numbers from 1 ,2 , 3,...
#[derive(Default, PartialEq, Debug, UtilsTupleIo, UtilsDefaultSerde)]
pub struct PositiveInteger (pub u32);

impl Validate for PositiveInteger {
    fn validate(&self) -> Result<(), String> { 
        if self.0 < "1".parse().unwrap() {
            return Err(format!("MinInclusive validation error: invalid value of 0! \nExpected: 0 >= 1.\nActual: 0 == {}", self.0));
        }
        Ok(())
    }
}

Compiler result:

error[E0283]: type annotations needed
   --> src/schema/types.rs:106:19
	|
106 |     	if self.0 < "1".parse().unwrap() {
	|               	^ cannot infer type for type `u32`
	|
	= note: cannot resolve `u32: std::cmp::PartialOrd<_>`

Process enumerations with namespaces used in their values

For the following type from soap-envelope.xsd

  <xs:simpleType name="faultcodeEnum">
    <xs:restriction base="xs:QName">
      <xs:enumeration value="tns:DataEncodingUnknown"/>
      <xs:enumeration value="tns:MustUnderstand"/>
      <xs:enumeration value="tns:Receiver"/>
      <xs:enumeration value="tns:Sender"/>
      <xs:enumeration value="tns:VersionMismatch"/>
    </xs:restriction>
  </xs:simpleType>

this generated code is desired:

#[derive(PartialEq, Debug, YaSerialize, YaDeserialize)]
pub enum FaultcodeEnum {
    #[yaserde(rename = "tns:DataEncodingUnknown")]
    DataEncodingUnknown,
    #[yaserde(rename = "tns:MustUnderstand")]
    MustUnderstand,
    #[yaserde(rename = "tns:Receiver")]
    Receiver,
    #[yaserde(rename = "tns:Sender")]
    Sender,
    #[yaserde(rename = "tns:VersionMismatch")]
    VersionMismatch,
    __Unknown__(String),
}

but the following is generated:

#[derive(Default, PartialEq, Debug, UtilsTupleIo, UtilsDefaultSerde)]
pub struct FaultcodeEnum(pub String);

Double xmlns for xsd

In bf-2.xsd file

<xsd:schema
 xmlns="http://www.w3.org/2001/XMLSchema"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"

Now the first value is being taken. I think it's right to take the last one, which will override the previous ones.

        xsd_ns: schema
            .namespaces()
            .iter()
            .find(|a| a.uri() == "http://www.w3.org/2001/XMLSchema")
            .cloned(),

Add common file loader and static storage

The original text and XML tree can be stored all the time the program is running. It would be quite convenient to have a common tool to load files and directories. This would also reduce problems with maintaining the XML node lifetimes and self-reference problems.

Implement WSDL operations generating

Currently, the parser/generator tested only with XSD files. We want it to be capable of generating code from WSDLs.

Note: this issue will be specified/split as some work regarding XSD finished.

Support for anyAttributes

<xs:complexType name="NoiseReductionOptions">
	<xs:sequence>
		<xs:element name="Level" type="xs:boolean">
			<xs:annotation>
				<xs:documentation>Indicates whether or not support Level parameter for NoiseReduction.</xs:documentation>
			</xs:annotation>
		</xs:element>
		<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded" />   <!-- first ONVIF then Vendor -->
	</xs:sequence>
	<xs:anyAttribute processContents="lax"/>
</xs:complexType>

Support enumerations with tricky values

Enumerations may have values with punctuation within it. Currently, the following XSD

<xs:simpleType name="RelationshipType">
  <xs:restriction base="xs:anyURI">
     <xs:enumeration value="http://www.w3.org/2005/08/addressing/reply"/>
  </xs:restriction>
</xs:simpleType>

translates to

#[derive(PartialEq, Debug, YaSerialize, YaDeserialize)]
pub enum RelationshipType {
   http::WwwW3Org200508AddressingReply,
__Unknown__(String)
}

We should eather escape punctuation characters or store enumeration as strings with a value validation.

Improve enum generation

For XSD types restricted by xs::enumeration either enum of values either String generated, depending on the presense of special characters in the enumeration values.

Turns out that ONVIF contain a lot of enumeration values with a hyphen:

<xs:simpleType name="StreamType">
	<xs:restriction base="xs:string">
		<xs:enumeration value="RTP-Unicast"/>
		<xs:enumeration value="RTP-Multicast"/>
	</xs:restriction>
</xs:simpleType>

Would be nice to have this type as enum (with values sanitiesed of hyphen) rather than just a String.

To achieve it, we need to make our enumeration processing more intelegent.

Add support for Array?

Hello! Thank you for this library ๐Ÿ™‚

https://cwmp-data-models.broadband-forum.org/cwmp-1-2.xsd
I am trying to generate code from the above XSD which references <xs:import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"/>

downloading the SOAP encoding xsd and running I think the issue is the group/Array but I am not sure.

The full error is:

$ ./target/debug/xsd-parser --input soap-encoding.xsd --output soap-encoding.
rs
thread 'main' panicked at 'internal error: entered unreachable code: Unsupported node:
 Element { tag_name: {http://www.w3.org/2001/XMLSchema}group, attributes: [Attribute { name: name, value: "Array" }], namespaces: [Namespace { name: Some("xs"), uri: "http://www.w3.org/2001/XMLSchema" }, Namespace { name: Some("tns"), uri: "http://schemas.xmlsoap.org/soap/encoding/" }] }
parent = Some(Element { tag_name: {http://www.w3.org/2001/XMLSchema}schema, attributes: [Attribute { name: targetNamespace, value: "http://schemas.xmlsoap.org/soap/encoding/" }], namespaces: [Namespace { name: Some("xs"), uri: "http://www.w3.org/2001/XMLSchema" }, Namespace { name: Some("tns"), uri: "http://schemas.xmlsoap.org/soap/encoding/" }] })
', xsd-parser/src/parser/node_parser.rs:41:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Thanks again for working on this library.

Implement validation trait for custom types

To generate validation for structs, our custom types, made for built-in XSD types processing, should support validation too. This might be tricky for time-related types since their values are not always comparable, and even otherwise, their ordering might be complicated. For now, we could skip some edge cases.

Name Collisions

Hello,

I have an XSD that I've used as input to the parser. Upon generation of code, it resulted in some struct fields to have name collisions or duplicate names with different associated types.

For example:
This XSD -> https://gist.github.com/mlevkov/a9a5f77473668e7d53f64a2b5ee3ccfa

contains a type called SegmentTemplateType, which has other sub-related types, some of these types have same field names, which through the expansion of types results in duplicate naming, as such:

#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(namespace = "urn:mpeg:dash:schema:mpd:2011")]
pub struct SegmentTemplateType {
    #[yaserde(attribute, rename = "media")]
    pub media: Option<String>,

    #[yaserde(attribute, rename = "index")]
    pub index: Option<String>,

    #[yaserde(attribute, rename = "initialization")]
    pub initialization: Option<String>,

    #[yaserde(attribute, rename = "bitstreamSwitching")]
    pub bitstream_switching: Option<String>,

    #[yaserde(rename = "SegmentTimeline")]
    pub segment_timeline: Option<SegmentTimelineType>,

    #[yaserde(rename = "BitstreamSwitching")]
    pub bitstream_switching: Option<Urltype>,

    #[yaserde(attribute, rename = "duration")]
    pub duration: Option<u32>,

    #[yaserde(attribute, rename = "startNumber")]
    pub start_number: Option<u32>,

    #[yaserde(rename = "Initialization")]
    pub initialization: Option<Urltype>,

    #[yaserde(rename = "RepresentationIndex")]
    pub representation_index: Option<Urltype>,

    #[yaserde(attribute, rename = "timescale")]
    pub timescale: Option<u32>,

    #[yaserde(attribute, rename = "presentationTimeOffset")]
    pub presentation_time_offset: Option<u64>,

    #[yaserde(attribute, rename = "indexRange")]
    pub index_range: Option<String>,

    #[yaserde(attribute, rename = "indexRangeExact")]
    pub index_range_exact: Option<bool>,

    #[yaserde(attribute, rename = "availabilityTimeOffset")]
    pub availability_time_offset: Option<f64>,

    #[yaserde(attribute, rename = "availabilityTimeComplete")]
    pub availability_time_complete: Option<bool>,
}

Notice that initialization appears twice and so as bitstream_switching.

I have taken a bit different approach in handling creating an XML parser based on the XSD case. I have taken the attributes and elements to the aggregate higher level type. As such, it provided an opportunity to explicitly identify parts of the type that belong to attribute and parts that belong to elements. Here is an example of the SegmentTemplateType following such an approach.

#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
struct SegmentTemplate {
    #[yaserde(flatten)]
    multi_segment_base: MultiSegmentBase,
    #[yaserde(flatten)]
    attribute: SegmentTemplateAttribute,
}

#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
#[yaserde(
prefix = "mpd",
namespace = "mpd: urn:mpeg:dash:schema:mpd:2011",
default_namespace = "mpd"
)]
struct SegmentTemplateAttribute {
    #[yaserde(rename = "media", attribute)]
    media: String,
    #[yaserde(rename = "index", attribute)]
    index: String,
    #[yaserde(rename = "initialization", attribute)]
    initialization: String,
    #[yaserde(rename = "bitstreamSwitching", attribute)]
    bistream_switching: String,
}

// <!-- Segment Timeline -->
#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
struct SegmentTimeline {
    #[yaserde(flatten)]
    element: SegmentTimelineElements
}

#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
#[yaserde(
prefix = "mpd",
namespace = "mpd: urn:mpeg:dash:schema:mpd:2011",
default_namespace = "mpd"
)]
struct SegmentTimelineElements {
    #[yaserde(rename = "S")]
    s: Vec<S>
}

#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
struct S {
    #[yaserde(flatten)]
    attribute: SAttributes
}

#[derive(Default, Debug, Clone, PartialEq, YaSerialize, YaDeserialize)]
#[yaserde(
prefix = "mpd",
namespace = "mpd: urn:mpeg:dash:schema:mpd:2011",
default_namespace = "mpd"
)]
struct SAttributes {
    #[yaserde(rename = "t", attribute)]
    t: u64,
    #[yaserde(rename = "n", attribute)]
    n: Option<u64>,
    #[yaserde(rename = "d", attribute)]
    d: u64,
    #[yaserde(rename = "r", attribute)]
    r: Option<i64>,
}

a work-in-progress version you can find here: https://gist.github.com/mlevkov/094a3c671b175bba5d0a6511d8c0d348

I'm not certain yet if the decision to consider "expansion/extension" as base_field the right one, but at the moment, I'm thinking of how to make sure there is no "confusion" or "collision" on the similar naming for various parts of the structure. Hence, I've not stumbled upon a case when collision would occur, but once I have seen the output from the generated effort by the xsd-parser-rs, I realized that it would be at least worthy of mention that such took place. Thus giving you an opportunity to consider such a case with an example.

Side point note, interesting that the various approaches you've taken are the very things that I've stumbled upon while making a parser for DASH media type. Kudos to the great thought process.

Add generated code compilation tests

As a developer I want to be able to easily tell if generated code compiles or not.
To accomplish this we need to find a way to write tests receiving xsd as input and verifying that generated code compiles and has expected structure (probably disregarding whitespaces).

missing comma in attribute listing

Hello,

I recently used your tool to generate a rust file to use with the yaserde library.

I've noticed that the generated file had a missing comma in the listing of attributes. Is that intended or not?

    #[yaserde(attribute, prefix = "xlink" rename = "actuate")]
    pub actuate: Option<xlink::Actuate>,

I would have expected to have the following:

    #[yaserde(attribute, prefix = "xlink", rename = "actuate")]
    pub actuate: Option<xlink::Actuate>,

notice , between prefix = "xlink" and rename = "actuate".

Thank you for the awesome effort, by the way ;).

Generate code from all related XSD's at once

As onvif-rs (https://github.com/lumeohq/onvif-rs) user I want all types from onvif-rs::schema fully comply with all XSD's used by onvif.xsd.

onvif.xsd dependency graph is a bit branchy and we have to reflect it in onvif_rs::schema module. To accomplish this we need to run xsd-parser-rs on all XSD's reachable from onvif.xsd and put the generated code into module structure of onvif-rs.

xsd-model: create abstract code level structs for all schema-top types

In the branch xsd-model, we need to create abstract code level structs for all types from xsd-parser/src/xsd_model/groups/schema_top.rs. In the scope of the same task, we need to implement conversions from XSD model level types to abstract code level types.

List of types:

  • TopLevelSimpleType
  • TopLevelComplexType
  • Group
  • AttributeGroup
  • TopLevelElement
  • TopLevelAttribute
  • Notation

UtilsTupleIo, UtilsDefaultSerde derive macros and Validate trait

Hello,

Thank you for your effort. I would like to ask how to activate the derive UtilsTupleIo, UtilsDefaultSerde? There is a frequent reference to the UtilsTupleIo, UtilsDefaultSerde, however, it is unclear as to what I need to include in the project in order to allow for these to exist over the struct. I've noticed that Validate is attached to the custom type, however, no reference is generated in the code base for such. Having to examine your code, even the one that is generated by default from the XML-parser binary, I see no definition of trait at all. However, I went about and added in my project, but I'm not certain whether that is the intended outcome.

Also, would it make sense to include some of your de/se overrides within the Yaserde library, instead of keeping it within your custom effort? I'm referring to UtilsTupleIo, UtilsDefaultSerde?

Thank you so much.

Made custom types for gDay, gMonth and so on

Currently, we are storing gDay, gMonth and so on as String. This is, obviosly, not the best thing to do.

Rust types for gMonth and other built-in XSD g...-types should both provide stored value as an integer and support proper (de)serialization with yaserde.

Add support for xs:any element

<xs:complexType name="MessageExtension">
  <xs:sequence>
    <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>   <!-- first Vendor then ONVIF -->
  </xs:sequence>
</xs:complexType>

Add support for ComplexContent and SimpleContent

<xs:complexType name="CertificateUsage">
	<xs:simpleContent>
		<xs:extension base="xs:string">
			<xs:attribute name="Critical" type="xs:boolean" use="required"/>
		</xs:extension>
	</xs:simpleContent>
</xs:complexType>

There is a duplicate field in the generated code

xmlmime.rs

// pub type ExpectedContentTypes = String;
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(prefix = "xmime", namespace = "xmime: http://www.w3.org/2005/05/xmlmime")]
pub struct Base64Binary {
    #[yaserde(attribute, prefix = "xmime" rename = "contentType")]
    pub content_type: Option<ContentType>,

    #[yaserde(attribute, prefix = "xmime" rename = "contentType")]
    pub content_type: Option<ContentType>,
}

Implement restriction for complexContent

ws-discovery.xsd:

  <xs:element name="AppSequence" type="tns:AppSequenceType"/>
  <xs:complexType name="AppSequenceType">
    <xs:complexContent>
      <xs:restriction base="xs:anyType">
        <xs:attribute name="InstanceId" type="xs:unsignedInt" use="required"/>
        <xs:attribute name="SequenceId" type="xs:anyURI"/>
        <xs:attribute name="MessageNumber" type="xs:unsignedInt" use="required"/>
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>

Add code to xsd-parser-rs/src/parser/restriction.rs:complex_content_restriction func
Add unittest.

https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms256061(v=vs.100)

https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms256053(v=vs.100)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.