如何解析XSD以从<;获取信息;xsd:simpleType>;使用C#的元素?
我有一个包含多个复杂类型和简单类型的XSD(文件的一部分如下所示)。我需要解析此文档,从复杂类型中引用的每个SimpleType中获取maxLength。谁能就如何实现这一点提出一些建议?我需要以一种通用的方式实现它,所以如果我查询“Setup\u Type”,它应该给出以下输出。谢谢大家! NewSetup/Amount=12(元素标记的名称属性由“/”分隔,maxLength由嵌套的simpleType分隔) 新闻设置/Name=50如何解析XSD以从<;获取信息;xsd:simpleType>;使用C#的元素?,c#,c#-4.0,xsd,C#,C# 4.0,Xsd,我有一个包含多个复杂类型和简单类型的XSD(文件的一部分如下所示)。我需要解析此文档,从复杂类型中引用的每个SimpleType中获取maxLength。谁能就如何实现这一点提出一些建议?我需要以一种通用的方式实现它,所以如果我查询“Setup\u Type”,它应该给出以下输出。谢谢大家! NewSetup/Amount=12(元素标记的名称属性由“/”分隔,maxLength由嵌套的simpleType分隔) 新闻设置/Name=50 <xsd:complexType name="Se
<xsd:complexType name="Setup_Type">
<xsd:sequence>
<xsd:element name="NewSetup" type="NewSetup_Type" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NewSetup_Type">
<xsd:sequence>
<xsd:element name="Amount" type="Amount_Type" minOccurs="1" maxOccurs="1" />
<xsd:element name="Name" type="Name_Type" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<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>
<xsd:simpleType name="Name_Type">
<xsd:annotation>
<xsd:documentation>Name</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
数量
名称
我的解决方案可能不是您想要的。可能您更喜欢使用System.Xml类来处理此类信息。我不知道你希望这个解析器有多通用,反正这些只是我的2美分。我的代码只是使用了正则表达式,它被设计成能够正确地面对99%的可能性(我猜)。有人会说这就像用枪射苍蝇。总之,就是这样:
using System.Text.RegularExpressions;
using System.IO;
static class Program
{
static void main()
{
XsdFile file = new XsdFile(@"c:\temp\test.xsd");
Console.WriteLine(file.Query("Setup_Type"));
}
}
public class XsdFile
{
Dictionary<string, XsdType> types;
public XsdFile(string path)
{
string xsdBody = File.ReadAllText(path);
types = XsdType.CreateTypes(xsdBody);
}
public string Query(string typename) {
return Query(typename, "");
}
private string Query(string typename, string parent)
{
XsdType type;
if (types.TryGetValue(typename, out type))
{
if (type.GetType() == typeof(ComplexType))
{
StringBuilder sb = new StringBuilder();
ComplexType complexType = (ComplexType)type;
foreach (string elementName in complexType.elements.Keys)
{
string elementType = complexType.elements[elementName];
sb.AppendLine(Query(elementType, parent + "/" + elementName));
}
return sb.ToString();
}
else if (type.GetType() == typeof(SimpleType))
{
SimpleType simpleType = (SimpleType)type;
return string.Format("{0} = {1}", parent, simpleType.maxLength);
}
else {
return "";
}
}
else
{
return "";
}
}
}
public abstract class XsdType
{
string name;
public XsdType(string name)
{
this.name = name;
}
public static Dictionary<string, XsdType> CreateTypes(string xsdBody)
{
Dictionary<string, XsdType> types = new Dictionary<string, XsdType>();
MatchCollection mc_types = Regex.Matches(xsdBody, @"<xsd:(?<kind>complex|simple)Type[\s\t]+(?<attributes>[^>]+)>(?<body>.+?)</xsd:\1Type>", RegexOptions.Singleline);
foreach (Match m_type in mc_types)
{
string typeKind = m_type.Groups["kind"].Value;
string typeAttributes = m_type.Groups["attributes"].Value;
string typeBody = m_type.Groups["body"].Value;
string typeName;
Match m_nameattribute = Regex.Match(typeAttributes, @"name[\s\t]*=[\s\t]*""(?<name>[^""]+)""", RegexOptions.Singleline);
if (m_nameattribute.Success)
{
typeName = m_nameattribute.Groups["name"].Value;
if (typeKind == "complex")
{
ComplexType current_type = new ComplexType(typeName);
MatchCollection mc_elements = Regex.Matches(typeBody, @"<xsd:element(?<attributes>.+?)/>", RegexOptions.Singleline);
foreach (Match m_element in mc_elements)
{
Dictionary<string, string> elementAttributes = ParseAttributes(m_element.Groups["attributes"].Value);
string elementName;
string elementType;
if (!elementAttributes.TryGetValue("name", out elementName))
continue;
if (!elementAttributes.TryGetValue("type", out elementType))
continue;
current_type.elements.Add(elementName, elementType);
}
types.Add(current_type.name, current_type);
}
else if (typeKind == "simple")
{
Match m_maxLength = Regex.Match(typeBody, @"<xsd:restriction[^>]+>.+?<xsd:maxLength.+?value=""(?<maxLength>[^""]+)""", RegexOptions.Singleline);
if (m_maxLength.Success)
{
string maxLength = m_maxLength.Groups["maxLength"].Value;
SimpleType current_type = new SimpleType(typeName);
current_type.maxLength = maxLength;
types.Add(current_type.name, current_type);
}
}
}
else
{
continue;
}
}
return types;
}
private static Dictionary<string, string> ParseAttributes(string value)
{
Dictionary<string, string> attributes = new Dictionary<string, string>();
MatchCollection mc_attributes = Regex.Matches(value, @"(?<name>[^=\s\t]+)[\s\t]*=[\s\t]*""(?<value>[^""]+)""", RegexOptions.Singleline);
foreach (Match m_attribute in mc_attributes)
{
attributes.Add(m_attribute.Groups["name"].Value, m_attribute.Groups["value"].Value);
}
return attributes;
}
}
public class SimpleType : XsdType
{
public string maxLength;
public SimpleType(string name)
: base(name)
{
}
}
public class ComplexType : XsdType
{
//(name-type)
public Dictionary<string, string> elements = new Dictionary<string,string>();
public ComplexType(string name)
: base(name)
{
}
}
使用System.Text.regular表达式;
使用System.IO;
静态类程序
{
静态void main()
{
XsdFile file=newxsdfile(@“c:\temp\test.xsd”);
Console.WriteLine(file.Query(“Setup_Type”);
}
}
公共类XsdFile
{
词典类型;
公共XsdFile(字符串路径)
{
字符串xsdBody=File.ReadAllText(路径);
types=XsdType.CreateTypes(xsdBody);
}
公共字符串查询(字符串类型名称){
返回查询(typename,“”);
}
私有字符串查询(字符串类型名称、字符串父级)
{
XsdType类型;
if(types.TryGetValue(typename,out类型))
{
if(type.GetType()==typeof(ComplexType))
{
StringBuilder sb=新的StringBuilder();
ComplexType ComplexType=(ComplexType)类型;
foreach(complexType.elements.Keys中的字符串elementName)
{
字符串elementType=complexType.elements[elementName];
sb.AppendLine(查询(elementType,parent+“/”+elementName));
}
使某人返回字符串();
}
else if(type.GetType()==typeof(SimpleType))
{
SimpleType SimpleType=(SimpleType)类型;
返回string.Format(“{0}={1}”,父级,simpleType.maxLength);
}
否则{
返回“”;
}
}
其他的
{
返回“”;
}
}
}
公共抽象类XsdType
{
字符串名;
公共XsdType(字符串名称)
{
this.name=名称;
}
公共静态字典CreateTypes(字符串xsdBody)
{
字典类型=新字典();
MatchCollection mc_types=Regex.Matches(xsdBody,@“]+)>(?。+)”,RegexOptions.Singleline);
foreach(在mc_类型中匹配m_类型)
{
字符串typeKind=m_type.Groups[“kind”].Value;
string typeAttributes=m_type.Groups[“attributes”].Value;
字符串typeBody=m_type.Groups[“body”].Value;
字符串类型名;
Match m_nameattribute=Regex.Match(typeAttributes,@“name[\s\t]*=[\s\t]*”(?[^”“]+)”,RegexOptions.Singleline);
if(m_nameattribute.Success)
{
typeName=m_nameattribute.Groups[“name”].Value;
if(typeKind==“复杂”)
{
ComplexType当前类型=新的ComplexType(类型名称);
MatchCollection mc_elements=Regex.Matches(typeBody,@“”,RegexOptions.Singleline);
foreach(匹配mc_元素中的m_元素)
{
Dictionary elementAttributes=ParseAttributes(m_element.Groups[“attributes”].Value);
字符串元素名;
字符串元素类型;
if(!elementAttributes.TryGetValue(“name”,out elementName))
继续;
如果(!elementAttributes.TryGetValue(“type”,out elementType))
继续;
当前类型.elements.Add(elementName,elementType);
}
类型.添加(当前类型.名称,当前类型);
}
else if(typeKind==“简单”)
{
Match m_maxLength=Regex.Match(typeBody,@“]+>。+?我以前也见过类似的问题(完全公开,我自己也问过类似的问题)。解析XSD不适合胆小的人
您基本上有两个选项,第一个更容易实现,但是可以通过对XSD的微小更改更容易地打破。第二个选项更健壮,但很难实现
选项1:
使用LINQ(或其他C#XML解析器,如果您愿意)解析XSD。由于XSD只是一个XML,您可以将其加载到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>
这并不能提供一种非常简单的方法来按类型名进行解析,特别是对于扩展类型。要使用这种方法,您需要知道要查找的每个元素的确切路径
选项2:
这对于一个快速的回答来说太复杂了(注意:请参阅下面的编辑-我花了一些时间整理了一个有效的解决方案),所以我想鼓励大家看看我自己在上面链接的问题。在其中,我链接了一个演示如何将XSD分解为多个部分,并可能允许您执行所需类型的搜索。您必须决定是否值得为其进行开发(该博客展示了一个带有XmlReader
的实现,该实现包含一个针对所讨论的XSD进行验证的XML,但是您可以通过直接加载XSD并对其进行解析来轻松实现这一点
2键一
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();
// 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));
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();
}
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;
}
var results = GetElementMaxLength("Setup_Type");
foreach (var item in results)
{
Console.WriteLine("{0} | {1}", item.Key, item.Value);
}
public class result_tree
{
public string nodevalue = "";
public bool IsTerminal { get { return ChildCount == 0; } }
public List<result_tree> children = new List<result_tree>();
public int ChildCount { get { return children.Count; } }
public result_tree(string v) { nodevalue = v; }
private void print_children(bool skip, string prefix)
{
if (IsTerminal)
Console.WriteLine(prefix + (prefix.Length==0?"":"/") + nodevalue);
else
foreach (result_tree rt in children)
rt.print_children(false,prefix + (prefix.Length == 0 ? "" : "/") + (skip?"":nodevalue));
}
public void print_children()
{
print_children(true,"");
}
}
static class Program
{
private static void ValidationCallBack(object sender, ValidationEventArgs args)
{
Console.WriteLine(args.Message);
}
public static result_tree results;
static string deref_simple(XmlSchemaSimpleType simp)
{
XmlSchemaSimpleTypeRestriction xsstr = (XmlSchemaSimpleTypeRestriction)simp.Content;
foreach (object o in xsstr.Facets)
{
if (o.GetType() == typeof(XmlSchemaMaxLengthFacet))
{
XmlSchemaMaxLengthFacet fac = (XmlSchemaMaxLengthFacet)o;
return fac.Value;
}
}
return "";
}
static result_tree deref_complex(XmlSchema xs, XmlSchemaComplexType cplx)
{
result_tree rt = new result_tree(cplx.Name);
if (cplx.Particle.GetType() == typeof(XmlSchemaSequence))
{
XmlSchemaSequence seq = (XmlSchemaSequence)cplx.Particle;
foreach (object o in seq.Items)
{
if (o.GetType() == typeof(XmlSchemaElement))
{
XmlSchemaElement elem = (XmlSchemaElement)o;
XmlQualifiedName name = elem.SchemaTypeName;
result_tree branch;
object referto = xs.SchemaTypes[name];
if (referto.GetType() == typeof(XmlSchemaComplexType))
{
branch = deref_complex(xs,(XmlSchemaComplexType)referto);
branch.nodevalue = elem.Name;
}
else if (referto.GetType() == typeof(XmlSchemaSimpleType))
{
XmlSchemaSimpleType st = (XmlSchemaSimpleType)referto;
branch = new result_tree(elem.Name + " = " + deref_simple(st).ToString());
}
else
{
branch = null;
}
if( branch != null )
rt.children.Add(branch);
}
}
}
return rt;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
StreamReader sr = new StreamReader("aschema.xml");
XmlSchema xs = XmlSchema.Read(sr, ValidationCallBack);
XmlSchemaSet xss = new XmlSchemaSet();
xss.Add(xs);
xss.Compile();
Console.WriteLine("Query: ");
string q = Console.ReadLine();
XmlQualifiedName xqn = new XmlQualifiedName(q);
if (xs.SchemaTypes.Contains(xqn))
{
object o = xs.SchemaTypes[xqn];
if (o.GetType() == typeof(XmlSchemaComplexType))
{
results = deref_complex(xs, (XmlSchemaComplexType)o);
results.print_children();
}
}
else
{
Console.WriteLine("Not found!");
}
}
}