私は過去に同様の質問をしたことがあります(完全な開示、私自身も同様の質問をしました)。XSDの解析は、気の弱い人向けではありません。
基本的に2つのオプションがあります。最初のオプションは実装が簡単ですが、XSDに小さな変更を加えることで簡単に壊すことができます。2つ目は、より堅牢ですが、実装が困難です。
オプション1:
XSDをLINQ(または必要に応じて他のC#XMLパーサー)で解析します。XSDは単なるXMLであるため、XSDをにロードして、XDocument
LINQを介して読み取ることができます。
独自の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>
MaxLengthにアクセスできます。
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();
これは、特に拡張型の場合、型名で解析するための非常に簡単な方法を提供しません。これを使用するには、探している各要素の正確なパスを知る必要があります。
オプション2:
これは非常に複雑すぎて簡単に答えることができません(注:以下の編集を参照してください-しばらく時間があり、実用的な解決策をまとめました)。そのため、上記でリンクした自分の質問を参照することをお勧めします。その中で、 XSDを真剣に細かく分割する方法を示し、必要な種類の検索を実行できる可能性のあるすばらしいブログをリンクしました。開発する価値があるかどうかを判断する必要があります(ブログには、XmlReader
問題のXSDに対して検証されたXMLを含む実装が示されていますが、XSDを直接ロードして解析することで、これを簡単に実現できます。
ブログで見つける2つの重要なアイデアは次のとおりです。
// 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));
昨年、複雑なデータ検証方法の一部としてXSDを解析するために同じことを実際に試しました。ブログのメソッドを自分の目的に合わせて調整するために何が起こっているのかを実際に理解するのに、1週間の大部分を要しました。それは間違いなくあなたが望むものを正確に実装するための最良の方法です。
スタンドアロンスキーマでこれを試してみたい場合は、XSDをXmlSchemaSet
オブジェクトにロードしてから、GlobalTypes
プロパティを使用して、探している特定のタイプを見つけることができます。
編集:
私は古いコードを取り出して、あなたを助けるためにコードをまとめ始めました。
最初にスキーマをロードします。
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();
}
次の方法では、提供したXSDに基づいて必要なものに近づけることができます。より複雑な構造を処理するのにかなり適応できるはずです。
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;
}
次に、使用法は非常に簡単です。メソッドを呼び出すだけGetElementMaxLength(String)
で、最大長として値を指定した形式で名前の辞書が返されます。
var results = GetElementMaxLength("Setup_Type");
foreach (var item in results)
{
Console.WriteLine("{0} | {1}", item.Key, item.Value);
}