Ich habe in der Vergangenheit gefragt ähnliche Fragen gesehen (vollständige Offenlegung, frage ich habe ein ähnliches question mich). Das Parsen einer XSD ist nichts für schwache Nerven.
Sie haben grundsätzlich 2 Optionen, erstens ist einfacher zu implementieren, aber kann leichter durch kleinere Änderungen an der XSD gebrochen werden. Der 2. ist robuster, aber schwer zu implementieren.
Option 1:
Parsen der XSD mit LINQ (oder einem anderen C# XML-Parser, wenn Sie bevorzugen). Da ein XSD nur ein XML ist, können Sie es in ein XDocument
laden und nur über LINQ lesen.
Für nur eine Probe Ihres eigenen XSD:
<xsd:simpleType name="Amount_Type">
<xsd:annotation>
<xsd:documentation>Amount</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="12" />
</xsd:restriction>
</xsd:simpleType>
Sie die MaxLength zugreifen:
var xDoc = XDocument.Load("your XSD path");
var ns = XNamespace.Get(@"http://www.w3.org/2001/XMLSchema");
var length = (from sType in xDoc.Element(ns + "schema").Elements(ns + "simpleType")
where sType.Attribute("name").Value == "Amount_Type"
from r in sType.Elements(ns + "restriction")
select r.Element(ns + "maxLength").Attribute("value")
.Value).FirstOrDefault();
Das ist nicht eine sehr einfache Methode für die Analyse von Typnamen bietet, insbesondere für längere Arten. Um dies zu verwenden, müssen Sie den genauen Pfad für jedes Element kennen, nach dem Sie suchen.
Option 2:
Das ist viel zu komplex für eine schnelle Antwort (Anmerkung: siehe bearbeiten unten - ich einige Zeit hatte und zusammen eine Arbeitslösung), so werde ich ermutigen, Sie schauen sich meine eigene Frage an, die ich oben verlinkt habe. Darin verknüpfte ich eine great blog, die zeigt, wie Sie die XSD ernsthaft in Teile zerlegen und möglicherweise ermöglichen Sie die Art der Suche, die Sie wollen. Sie müssen entscheiden, ob es sich lohnt, sie zu entwickeln (das Blog zeigt eine Implementierung mit XmlReader
, die ein XML enthält, das gegen die betreffende XSD validiert wird, aber Sie können dies einfach durch direktes Laden der XSD und Parsing erreichen.
2 Schlüsselidee im Blog zu finden sind:
// in the getRestriction method (reader in this context is an `XmlReader` that
// contains a XML that is being validated against the specific XSD
if (reader.SchemaInfo.SchemaElement == null) return null;
simpleType = reader.SchemaInfo.SchemaElement.ElementSchemaType as XmlSchemaSimpleType;
if (simpleType == null) return null;
restriction = simpleType.Content as XmlSchemaSimpleTypeRestriction;
// then in the getMaxLength method
if (restriction == null) return null;
List<int> result = new List<int>();
foreach (XmlSchemaObject facet in restriction.Facets) {
if (facet is XmlSchemaMaxLengthFacet) result.Add(int.Parse(((XmlSchemaFacet) facet).Value));
Ich habe versucht, tatsächlich das gleiche letztes Jahr ein XSD als Teil einer komplizierten Datenvalidierungsmethode zu analysieren. Ich brauchte den größten Teil einer Woche, um wirklich zu verstehen, was passierte, um die Methoden im Blog an meine Zwecke anzupassen. Es ist definitiv der beste Weg, genau das zu implementieren, was Sie wollen.
Wenn Sie dies mit einem eigenständigen Schema versuchen möchten, können Sie die XSD in ein XmlSchemaSet
Objekt laden und dann die GlobalTypes
-Eigenschaft verwenden, um den gesuchten Typ zu finden.
EDIT: zog ich meinen alten Code auf und begann den Code zusammenzustellen, Ihnen zu helfen.
XmlSchemaSet set; // this needs to be accessible to the methods below,
// so should be a class level field or property
using (var fs = new FileStream(@"your path here", FileMode.Open)
{
var schema = XmlSchema.Read(fs, null);
set = new XmlSchemaSet();
set.Add(schema);
set.Compile();
}
Die folgenden Methoden geben, sollten Sie in der Nähe zu dem, was Sie wollen auf der Grundlage der XSD Sie bereitgestellt:
Erstes Ihr Schema laden. Es sollte ziemlich anpassungsfähig sein, um mit komplexeren Strukturen umzugehen.
public Dictionary<string, int> GetElementMaxLength(String xsdElementName)
{
if (xsdElementName == null) throw new ArgumentException();
// if your XSD has a target namespace, you need to replace null with the namespace name
var qname = new XmlQualifiedName(xsdElementName, null);
// find the type you want in the XmlSchemaSet
var parentType = set.GlobalTypes[qname];
// call GetAllMaxLength with the parentType as parameter
var results = GetAllMaxLength(parentType);
return results;
}
private Dictionary<string, int> GetAllMaxLength(XmlSchemaObject obj)
{
Dictionary<string, int> dict = new Dictionary<string, int>();
// do some type checking on the XmlSchemaObject
if (obj is XmlSchemaSimpleType)
{
// if it is a simple type, then call GetMaxLength to get the MaxLength restriction
var st = obj as XmlSchemaSimpleType;
dict[st.QualifiedName.Name] = GetMaxLength(st);
}
else if (obj is XmlSchemaComplexType)
{
// if obj is a complexType, cast the particle type to a sequence
// and iterate the sequence
// warning - this will fail if it is not a sequence, so you might need
// to make some adjustments if you have something other than a xs:sequence
var ct = obj as XmlSchemaComplexType;
var seq = ct.ContentTypeParticle as XmlSchemaSequence;
foreach (var item in seq.Items)
{
// item will be an XmlSchemaObject, so just call this same method
// with item as the parameter to parse it out
var rng = GetAllMaxLength(item);
// add the results to the dictionary
foreach (var kvp in rng)
{
dict[kvp.Key] = kvp.Value;
}
}
}
else if (obj is XmlSchemaElement)
{
// if obj is an XmlSchemaElement, the you need to find the type
// based on the SchemaTypeName property. This is why your
// XmlSchemaSet needs to have class-level scope
var ele = obj as XmlSchemaElement;
var type = set.GlobalTypes[ele.SchemaTypeName];
// once you have the type, call this method again and get the dictionary result
var rng = GetAllMaxLength(type);
// put the results in this dictionary. The difference here is the dictionary
// key is put in the format you specified
foreach (var kvp in rng)
{
dict[String.Format("{0}/{1}", ele.QualifiedName.Name, kvp.Key)] = kvp.Value;
}
}
return dict;
}
private Int32 GetMaxLength(XmlSchemaSimpleType xsdSimpleType)
{
// get the content of the simple type
var restriction = xsdSimpleType.Content as XmlSchemaSimpleTypeRestriction;
// if it is null, then there are no restrictions and return -1 as a marker value
if (restriction == null) return -1;
Int32 result = -1;
// iterate the facets in the restrictions, look for a MaxLengthFacet and parse the value
foreach (XmlSchemaObject facet in restriction.Facets)
{
if (facet is XmlSchemaMaxLengthFacet)
{
result = int.Parse(((XmlSchemaFacet)facet).Value);
break;
}
}
return result;
}
Dann wird die Nutzung ist ziemlich einfach, Sie müssen nur die GetElementMaxLength(String)
Methode aufrufen und es wird ein Wörterbuch der Namen in dem Format, das Sie mit dem Wert als die maximale Länge versehen zurück:
var results = GetElementMaxLength("Setup_Type");
foreach (var item in results)
{
Console.WriteLine("{0} | {1}", item.Key, item.Value);
}
Vielen Dank für die tollen Lösungen. Es war sehr hilfreich, sich den Code anzuschauen. Bis jetzt habe ich @ psubse2003 Lösung versucht und es funktioniert gut für mich. – Jyina