Является svcutil.exe заменой для xsd.exe?
Я использую xsd.exe для создания некоторых классов С# из файла .xsd. Я столкнулся с той же проблемой, что и здесь, и на других сайтах, где xsd.exe генерирует массивы Type [] вместо общих коллекций List для типов в файле .xsd. Некоторые люди предположили, что svcutil.exe можно использовать в качестве замены для xsd.exe, если вы передаете параметр /dataContractOnly в svcutil.exe. Однако кажется, что эти люди ошибаются, потому что svcutil.exe фактически генерирует свойства массива System.Xml.XmlNode [] вместо создания типов на основе схемы в файле .xsd.
Например, учитывая эту простую схему .xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:complexType name="Employee">
<xs:all>
<xs:element name="FirstName" type="xs:string"></xs:element>
<xs:element name="LastName" type="xs:string"></xs:element>
</xs:all>
</xs:complexType>
<xs:element name="Employees">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="Employee" type="Employee"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
'xsd.exe/classes Example.xsd' генерирует:
public partial class Employees {
private Employee[] employeeField;
public Employee[] Employee {
get { return this.employeeField; }
set { this.employeeField = value; }
}
}
public partial class Employee {
private string firstNameField;
private string lastNameField;
public string FirstName {
get { return this.firstNameField; }
set { this.firstNameField = value; }
}
public string LastName {
get { return this.lastNameField; }
set { this.lastNameField = value; }
}
}
'svcutil.exe/target: code/dataContractOnly/serializer: XmlSerializer/importXmlTypes/collectionType:System.Collections.Generic.List`1 Example.xsd' генерирует:
public partial class Employee : object, System.Runtime.Serialization.IExtensibleDataObject{
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string FirstNameField;
private string LastNameField;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData{
get{ return this.extensionDataField; }
set{ this.extensionDataField = value; }
}
public string FirstName{
get{ return this.FirstNameField; }
set{ this.FirstNameField = value; }
}
public string LastName{
get{ return this.LastNameField; }
set{ this.LastNameField = value; }
}
}
public partial class Employees : object, System.Xml.Serialization.IXmlSerializable{
private System.Xml.XmlNode[] nodesField;
private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName("Employees", "http://tempuri.org/XMLSchema.xsd");
public System.Xml.XmlNode[] Nodes{
get{ return this.nodesField; }
set{ this.nodesField = value; }
}
public void ReadXml(System.Xml.XmlReader reader){
this.nodesField = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(reader);
}
public void WriteXml(System.Xml.XmlWriter writer){
System.Runtime.Serialization.XmlSerializableServices.WriteNodes(writer, this.Nodes);
}
public System.Xml.Schema.XmlSchema GetSchema(){
return null;
}
public static System.Xml.XmlQualifiedName ExportSchema(System.Xml.Schema.XmlSchemaSet schemas){
System.Runtime.Serialization.XmlSerializableServices.AddDefaultSchema(schemas, typeName);
return typeName;
}
}
-
Действительно ли svcutil.exe является заменой для xsd.exe? Полученный результат кажется совсем другим.
-
В этот момент мне кажется, что мне нужно будет использовать xsd.exe для создания классов из моего .xsd файла, а затем вручную настроить его, чтобы получить его в форме, которую я хочу. Я понимаю, что использование чисто сгенерированного кода было бы идеальным, но мне было интересно, если другие люди используют xsd.exe в качестве отправной точки, а затем работают оттуда или если мне нужно вообще рассмотреть другой подход?
-
Есть ли какие-либо обновления для xsd.exe в Visual Studio 2010?
Ответы
Ответ 1
Да, svcutil.exe
может использоваться как замена для xsd.exe
, но похоже, что у вас возникли проблемы с созданием генерических коллекций. svcutil.exe
имеет переключатель collectionType
, который позволяет указать тип, который будет использоваться для коллекции:
svcutil /o:Svc.cs /ct:System.Collections.Generic.List`1 http://example.com
Ответ 2
Разъяснение
Эндрю Хэр ответит выше будет, но пример команды, который jameswelle вставил чуть выше его последнего раздела кода:
svcutil.exe /target:code /dataContractOnly /serializer:XmlSerializer /importXmlTypes /collectionType:System.Collections.Generic.List`1 Example.xsd
работает not, потому что как указано в MSDN.,. /r и /ct для ссылочных типов коммутаторы предназначены для создания контрактов данных. Эти переключатели не работают при использовании XmlSerializer.
НТН.
Ответ 3
Я бы просто создал свой собственный xsd.exe. Извините, если у вас возникли проблемы с вставкой, но если вы скопируете этот код в свой основной:
XmlSchemas xsds = new XmlSchemas();
xsds.Add(xsd);
xsds.Compile(null, true);
XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);
// create the codedom
CodeNamespace codeNamespace = new CodeNamespace(strNamespace);
XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace);
List<XmlTypeMapping> maps = new List<XmlTypeMapping>();
foreach (XmlSchemaType schemaType in xsd.SchemaTypes.Values)
{
maps.Add(schemaImporter.ImportSchemaType(schemaType.QualifiedName));
}
foreach (XmlSchemaElement schemaElement in xsd.Elements.Values)
{
maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName));
}
foreach (XmlTypeMapping map in maps)
{
codeExporter.ExportTypeMapping(map);
}
ReplaceArrayWithList(codeNamespace);
// Check for invalid characters in identifiers
CodeGenerator.ValidateIdentifiers(codeNamespace);
// output the C# code
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
using (StreamWriter writer = new StreamWriter(strCsPath, false))
{
codeProvider.GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions());
}
}
private static void ReplaceArrayWithList(CodeNamespace codeNamespace)
{
codeNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
foreach (CodeTypeDeclaration codeType in codeNamespace.Types)
{
foreach (CodeTypeMember member in codeType.Members)
{
if (member is CodeMemberField)
{
CodeMemberField field = (CodeMemberField)member;
if (field.Type.ArrayRank > 0)
{
CodeTypeReference type = new CodeTypeReference();
type.BaseType = "List<" + field.Type.BaseType + ">";
field.Type = type;
}
}
if (member is CodeMemberProperty)
{
CodeMemberProperty property = (CodeMemberProperty)member;
if (property.Type.ArrayRank > 0)
{
CodeTypeReference type = new CodeTypeReference();
type.BaseType = "List<" + property.Type.BaseType + ">";
property.Type = type;
}
}
}
}
}
}
}
Ответ 4
Я тестировал те же команды на другой схеме, и получил аналогичные "мусорные" результаты от svcutil. Таким образом, возможно, это способ заставить его работать как xsd.exe, но пока все, что я видел, гораздо менее полезны.
Обновленный ответ: я обнаружил, что многие из этих общих массивов узлов xml были заменены сильными типами, когда все ссылочные XSD принудительно включены. В моем случае у меня есть много файлов xsd, на которые все ссылаются друг на друга, но svcutil, похоже, не включает их. я должен был вместо этого сказать, чтобы использовать *.xsd, чтобы получить их все.
Ответ 5
Я нашел Xsd2Code намного лучше, чем xsd.exe делает именно то, что вам нужно. Глянь сюда:
http://xsd2code.codeplex.com/