使用类

时间:2016-08-01 14:46:21

标签: c# xml reflection

我有一个从数据库获取数据的类,它以分层数据的形式获取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.有人可以帮我弄清楚我去了哪里吗?

2 个答案:

答案 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

  • 创建 sample.xml 文件,内容就是您的示例
  • 找到并运行XSD工具xsd sample.xml /outputDir:XmlSerialization
  • 应生成.xsd文件,您可能需要修改某些元素类型
    • 例如 SecurityGroup.Id 可能会自动生成为xs:string,将其更改为xs:int
    • 如果您知道该属性始终设置
    • 或删除 SecurityUser.userId minOccurs="0"
    • 您可能必须从
    • 修复 SecurityGroup.SecurityUsers
<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 xsd sample.xsd /outputDir:XmlSerialization /c
  • 运行XSD工具
  • 应生成.cs文件,验证它
    • 我需要手动修复XSD,因为 SecurityGroup.SecurityUser 是作为2-dim数组生成的
  • 在项目/脚本中使用自动生成的类
  • 创建一个XmlSerializer - 请参阅Example - 并反序列化XML字符串,然后访问数据
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;
}
  • 查看我手动修复的XSD here,已验证使用您的示例数据

答案 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>

我希望这有助于其他人!