我有一个从数据库获取数据的类,它以分层数据的形式获取as xml数据。
下面的是数据样本:
<SecurityGroups>
<SecurityGroup>
<Id>1</Id>
<Name>View</Name>
</SecurityGroup>
<SecurityGroup>
<Id>2</Id>
<Name>Fill</Name>
<SecurityUsers>
<SecurityUser>
<securityId>2</securityId>
<userId>2</userId>
<username>Fill</username>
</SecurityUser>
<SecurityUser>
<securityId>2</securityId>
<userId>3</userId>
<username>FillOne</username>
</SecurityUser>
<SecurityUser>
<securityId>2</securityId>
<userId>4</userId>
<username/></SecurityUser>
</SecurityUsers>
</SecurityGroup>
<SecurityGroup>
<Id>3</Id>
<Name>Update</Name>
<SecurityUsers>
<SecurityUser>
<securityId>3</securityId>
<userId>5</userId>
<username>Update</username>
</SecurityUser>
<SecurityUser>
<securityId>3</securityId>
<userId>6</userId>
<username>UpdateOne</username>
</SecurityUser>
</SecurityUsers>
</SecurityGroup>
<SecurityGroup>
<Id>4</Id>
<Name>Admin</Name>
<SecurityUsers>
<SecurityUser>
<securityId>4</securityId>
<userId>1</userId>
<username>JTays</username>
</SecurityUser>
</SecurityUsers>
</SecurityGroup>
哪个效果很好!现在,我有一个类使用反射从xml转换为我最终将在树视图中使用的模型。 以下是整个班级。
模型是:
[XmlRootAttribute(Namespace = "", IsNullable = false)]
public class SecurityGroup
{
[XmlElementAttribute(Form = XmlSchemaForm.Unqualified)]
public int Id { get; set; }
[XmlElementAttribute(Form = XmlSchemaForm.Unqualified)]
public string Name { get; set; }
[XmlElementAttribute("SecurityUser",
Form = XmlSchemaForm.Unqualified)]
public List<SecurityUser> SecurityUsers { get; set; }
}
public class SecurityUser:IEntity
{
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public int SecurityId { get; set; }
[XmlElementAttribute(Form = XmlSchemaForm.Unqualified)]
public int UserId { get; set; }
[XmlElementAttribute(Form = XmlSchemaForm.Unqualified)]
public string Username { get; set; }
public int Id { get; set; }
}
这是转换的类。
public class AdminManager : IAdminService
{
public IEnumerable<SecurityGroup> SecurityGroups()
{
IEnumerable<SecurityGroup> list = null;
XmlDocument xmlDoc = new XmlDocument();
using (var c = new FMContext())
{
var xmlData = c.Database.SqlQuery<string>("AllSecurtyUsersProc").FirstOrDefault();
if (xmlData != null)
{
xmlDoc.LoadXml(xmlData);
list = ConvertXmlToClass<SecurityGroup>(xmlDoc, "/SecurityGroups/SecurityGroup");
}
}
return list;
}
public static IEnumerable<T> ConvertXmlToClass<T>( XmlDocument doc, string nodeString)
where T:class, new()
{
var xmlNodes = doc.SelectNodes(nodeString);
List<T> list = new List<T>();
foreach (XmlNode node in xmlNodes)
{
var item = GetNewItem<T>(node);
list.Add(item);
}
return list;
}
public static T GetNewItem<T>(XmlNode node)
where T:class, new()
{
var type = typeof (T);
var item = new T();
var properties = type.GetProperties();
foreach (var property in properties)
{
var propertyType = property.PropertyType;
var propertyName = property.Name;
object value = null;
if (IsEnumerable(property))
{
value = GetNodeCollectionValue(property,node);
}
else
{
value = GetNodeValue(node, propertyName);
}
if (value!=null)
{
property.SetValue(item, Convert.ChangeType(value, propertyType), null);
}
}
return item;
}
private static object GetNodeCollectionValue(PropertyInfo property, XmlNode node)
{
var doc = new XmlDocument();
var itemType = property.PropertyType.GenericTypeArguments[0];
var xml = $"<{property.Name}><{itemType.Name}>{node.InnerXml}</{itemType.Name}></{property.Name}>";
doc.LoadXml(xml);
if (itemType != null)
{
var type = typeof (AdminManager);
var methodInfo = type.GetMethod("ConvertXmlToClass");
if (methodInfo!=null)
{
var method = methodInfo.MakeGenericMethod(itemType);
if (method != null)
{
object[] args = {doc, property.Name};
object result = method.Invoke(null, args);
return result;
}
}
}
return new object();
}
private static bool IsEnumerable(PropertyInfo property)
{
var type = property.PropertyType;
return typeof (IEnumerable).IsAssignableFrom(type) && type.IsGenericType;
}
private static object GetNodeValue(XmlNode node, string nodeName)
{
var i = node[nodeName]?.InnerText;
return i ?? null;
}
}
好的,现在我的问题。我的问题是,当它转换它没有获得SecurtyUsers
类的正确数据时,它将它们作为对象添加,但是一切都是null或0.有人可以帮我弄清楚我去了哪里吗?
答案 0 :(得分:1)
首先:您的示例XML不包含结束标记</SecurityGroups>
。
在您的 GetNodeCollectionValue 中,您传递了property.Name
但不应该是property.Name + "/" + itemType.Name
,因为您想要访问该节点的子节点?
此外,不会遍历node.InnerXml
,您会一次又一次地传递相同的节点。
我强烈建议使用.Net XML反序列化器,而不是重新发明轮子。
Generate XML示例的XML架构。然后从XSD创建.Net类。使用阅读器将XML从服务器传递到StringReader和Deserialize。然后只需从类实例中访问SecurityGroup
。
手动或使用XSD.exe
创建XML Schema(您将需要Windows SDK)。请参阅Examples。
xsd sample.xml /outputDir:XmlSerialization
.xsd
文件,您可能需要修改某些元素类型
xs:string
,将其更改为xs:int
minOccurs="0"
<xs:element name="SecurityUsers" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="SecurityUser" minOccurs="0" maxOccurs="unbounded">
要
<xs:element name="SecurityUsers" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="SecurityUser" maxOccurs="unbounded">
xsd sample.xsd /outputDir:XmlSerialization /c
.cs
文件,验证它
SecurityGroups deserialized;
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(SecurityGroups));
using (var stringReader = new System.IO.StringReader(xmlData))
{
deserialized = serializer.Deserialize(stringReader) as SecurityGroups;
}
答案 1 :(得分:0)
我发现了问题,就是我将整个xml传递给public override void Up()
{
DropIndex("dbo.PinnacleAccount", new[] { "User_Id" });
RenameColumn(table: "dbo.PinnacleAccount", name: "User_Id", newName: "UserId");
DropPrimaryKey("dbo.PinnacleAccount");
AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(nullable: false, maxLength: 128));
AddPrimaryKey("dbo.PinnacleAccount", "UserId");
CreateIndex("dbo.PinnacleAccount", "UserId");
DropColumn("dbo.PinnacleAccount", "Id");
DropColumn("dbo.PinnacleAccount", "UserIdOld");
}
public override void Down()
{
AddColumn("dbo.PinnacleAccount", "UserIdOld", c => c.String(nullable: false));
AddColumn("dbo.PinnacleAccount", "Id", c => c.Guid(nullable: false, identity: true));
DropIndex("dbo.PinnacleAccount", new[] { "UserId" });
DropPrimaryKey("dbo.PinnacleAccount");
AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(maxLength: 128));
AddPrimaryKey("dbo.PinnacleAccount", "Id");
RenameColumn(table: "dbo.PinnacleAccount", name: "UserId", newName: "User_Id");
CreateIndex("dbo.PinnacleAccount", "User_Id");
}
方法。我已修复此问题,下面是工作代码。
<a popover="{{tooltipValue}}" popover-trigger="mouseenter" href="#"><img class="img" /></a>
我希望这有助于其他人!