在XML中存储关系数据

时间:2008-09-26 19:58:52

标签: c# xml

我想知道在XML中存储关系数据结构的最佳实践是什么。特别是,我想知道强制执行节点顺序的最佳实践。例如,假设我有三个对象:SchoolCourseStudent,其定义如下:

class School
{
    List<Course> Courses;
    List<Student> Students;
}

class Course
{
    string Number;
    string Description;
}

class Student
{
    string Name;
    List<Course> EnrolledIn;
}

我会将这样的数据结构存储在XML中,如下所示:

<School>
    <Courses>
        <Course Number="ENGL 101" Description="English I" />
        <Course Number="CHEM 102" Description="General Inorganic Chemistry" />
        <Course Number="MATH 103" Description="Trigonometry" />
    </Courses>
    <Students>
        <Student Name="Jack">
            <EnrolledIn>
                <Course Number="CHEM 102" />
                <Course Number="MATH 103" />
            </EnrolledIn>
        </Student>
        <Student Name="Jill">
            <EnrolledIn>
                <Course Number="ENGL 101" />
                <Course Number="MATH 103" />
            </EnrolledIn>
        </Student>
    </Students>
</School>

通过这种方式订购XML,我可以先解析Courses。然后,当我解析Students时,我可以查找Course列表中EnrolledInNumber)中列出的每个School.Courses。这将为我提供一个对象引用,以添加到EnrolledIn中的Student列表。但是,如果StudentsCourses之前出现,则无法进行此类查找以获取对象引用。 (由于尚未填充School.Courses。)

那么在XML中存储关系数据的最佳实践是什么?    - 我应该强制Courses必须始终在Students之前吗?    - 我是否应该容忍任何排序并在遇到我尚未见过的对象时创建一个存根Course对象? (最后在最终达到Course的定义时进行扩展。)    - 还有其他方法我应该将对象持久化/加载到XML中吗? (我目前正在所有业务对象上实施SaveLoad方法,并使用System.Xml.XmlDocument及其关联类手动完成所有这些操作。)

我习惯于使用SQL中的关系数据,但这是我第一次尝试在XML中存储非平凡的关系数据结构。我们非常感谢您提供的关于我应该如何进行的任何建议。

8 个答案:

答案 0 :(得分:2)

虽然您可以使用&lt; xsd:sequence&gt;指定子元素的顺序,但要求子对象按特定顺序排列,您的系统会变得不那么灵活(即使用记事本更难更新)。

最好的办法是解析所有数据,然后执行您需要执行的操作。请勿在解析过程中采取行动。


显然,XML的设计及其背后的数据阻止了将单个POCO序列化为XML。您需要控制序列化和反序列化逻辑,以便将对象解除挂钩并重新挂钩。

我建议创建一个自定义序列化程序来构建此对象图的xml表示。因此,它不仅可以控制序列化的顺序,还可以处理节点不在预期顺序中的情况。您可以执行其他操作,例如添加自定义属性以用于将对象链接在一起,这些对象在序列化的对象上不作为公共属性存在。

创建xml就像在对象上迭代一样简单,构建XElements集合,并将对象的预期表示形式为xml。当你完成后,你可以将它们拼接成一个XDocument并从中抓取xml。您可以在背面的xml上进行多次传递,以重新创建对象图并恢复所有引用。

答案 1 :(得分:2)

在使用XML时,不要在SQL或关系中思考,因为没有顺序约束。

但是,您可以随时使用XPath查询XML文档的任何部分。您首先需要课程,然后是“//课程/课程”。您希望接下来的学生注册,然后是“//学生/学生/注册/课程”。

最重要的是......因为XML存储在一个文件中,所以不要认为你所有的访问都是串行的。


我发布了一个单独的问题"Can XPath do a foreign key lookup across two subtrees of an XML?",以澄清我的立场。该解决方案显示了如何使用XPath对XML数据进行关系查询。

答案 2 :(得分:1)

节点排序仅在您需要对数据进行仅向前处理时才很重要,例如:使用XmlReader或SAX解析器。如果您要在处理它之前将XML读入DOM(如果您使用的是XmlDocument,那么节点顺序并不重要)。更重要的是,XML的结构使您可以有效地使用XPath查询它,即无需使用“//”。

如果你看一下DataSetGenerator产生的模式,你会发现没有与DataTable级元素相关的排序。可能是ADO处理未在模式中表示的某些序列中的元素(例如,一次一个DataTable),或者ADO可以执行仅向前处理,并且在完全读取DataSet之前不强制执行关系约束。我不知道。但很明显,ADO不会将处理顺序与文档顺序相结合。

(是的,您可以在XML模式中指定子元素的顺序;这就是xs:sequence的作用。如果您不希望强制执行节点顺序,则使用无限制的xs:choice。)

答案 3 :(得分:0)

根据经验,XML不是存储关系数据的最佳选择。你调查了YAML吗?你有选择吗?

如果不这样做,一种安全的方法是对XML进行严格的DTD并强制执行。您也可以按照建议保留创建的对象的哈希值。这样,如果学生创建课程,您可以保留该课程,以便在标签被点击时进行更新。

另外请记住,您可以使用XPath查询直接访问特定节点,因此无论XML文档中的位置如何,您都可以首先强制解析课程。 (通过dacracot做出更完整的答案)

答案 4 :(得分:0)

订单在XML中通常不重要。在这种情况下,Courses可能会在Students之后出现。您解析XML,然后对整个数据进行查询。

答案 5 :(得分:0)

XML对于关系数据来说绝对不是一个友好的地方。

如果你绝对需要这样做,那么我会推荐一种时髦的倒置逻辑。

在你的例子中,你有许多学生开设的许多课程的学校。

您的XML可能会这样:

<School>
    <Students>
        <Student Name="Jack">
            <EnrolledIn>
                <Course Number="CHEM 102" Description="General Inorganic Chemistry" />
                <Course Number="MATH 103" Description="Trigonometry" />
            </EnrolledIn>
        </Student>
        <Student Name="Jill">
            <EnrolledIn>
                <Course Number="ENGL 101" Description="English I" />
                <Course Number="MATH 103" Description="Trigonometry" />
            </EnrolledIn>
        </Student>
    </Students>
</School>

这显然不是重复性最小的方法(它是关系数据!),但它很容易解析。

答案 6 :(得分:0)

您还可以使用两个XML文件,一个用于课程,另一个用于学生。在第二步之前打开并解析第一个。

答案 7 :(得分:0)

我已经有一段时间了,但我似乎记得在xml文件的一部分中做了“事物”的基本集合,并使用模式功能 keyref 参考。我找到了一些例子here。如果这不是你想要的,我道歉。