【问题标题】:XQuery with three separate XML files具有三个独立 XML 文件的 XQuery
【发布时间】:2015-11-10 03:00:12
【问题描述】:

在尝试学习 XQuery 时,我正在尝试编写一个从 三个 两个单独的 XML 文件中选择信息的查询。我对 XQuery 有一点经验,但是我想不出一种构建这种查询的好方法。这是每个 XML 文件中的信息。

Person.xml

<AllPersons>
  <Person>
    <Name>Jinchao Henson</Name>
    <ID>118784412</ID>
  </Person>
  <Person>
    <Name>Min Tuyet</Name>
    <ID>201586985</ID>
  </Person>
  <Person>
    <Name>John Basaraba</Name>
    <ID>124208644</ID>
  </Person>
  <Person>
    <Name>Richard Ellison</Name>
    <ID>997111094</ID>
  </Person>
  ...
</AllPersons>

Student.xml

<AllStudents>
  <Student>
    <StudentID>118784412</StudentID>
    <MentorID>201586985</MentorID>
  </Student>
  <Student>
    <StudentID>124208644</StudentID>
    <MentorID>997111094</MentorID>
  </Student>
  ...
</AllStudents>

Faculty.xml

<AllFaculty>
  <Faculty>
    <FacultyID>201586985</FacultyID>
    <Rank>Professor</Rank>
  </Faculty>
  <Faculty>
    <FacultyID>997111094</FacultyID>
    <Rank>Reader</Rank>
  </Faculty>
  ...
</AllFaculty>

一个家庭作业问题是要求选择每个学生和他们的导师。我试图编写一个循环遍历学生的查询,选择学生节点,然后为 Person 和 Faculty 节点设置两个 let 表达式,然后返回一个学生的姓名和一个教师的姓名,但无法让它工作。我还尝试了一个循环遍历学生的查询,一个用于教师的 let 表达式,一个将 StudentID 匹配到 FacultyID 并将 StudentID 匹配到 Person/ID 的 where 子句,然后返回该 Person/Name,然后遍历匹配 ID 和的教师返回名称。

非常感谢任何帮助。谢谢。

编辑:感谢您的建议。我清理了 XML 示例,这是一个尝试:

for $student in doc("../Student.xml")//Student
let $faculty := doc("../Faculty.xml")//Faculty
let $person := doc("../Person.xml")//Person
where $student/MentorID = $faculty/FacultyID and $student/StudentID = $person/ID
return
  <StudentMentor>{
      $person/Name,
      <Mentor>{
        for $personTwo in doc("../Person.xml")//Person
          where $personTwo/ID = $faculty/FacultyID
          return $personTwo/Name
      }</Mentor>
    }
 </StudentMentor> 
}

我对 XQuery 还很陌生,所以我不知道构建这个查询的最佳方式。

编辑2:仔细查看数据后,我想我什至不需要Faculty.xml文件,我会尝试更好的(实际可行的)解决方案。

编辑 3:这是我的工作解决方案,请告诉我如何提高效率。

for $student in doc("../Student.xml")//Student
let $personS := doc("../Person.xml")//Person[ID = $student/StudentID]
for $personM in doc("../Person.xml")//Person[ID = $student/MentorID]
return 
  <StudentMentor>
    <Student>{$personS/Name}</Student>,
    <Mentor>{$personM/Name}</Mentor>
  </StudentMentor>

【问题讨论】:

  • 为什么不显示您尝试过的查询(但无法开始工作)?对它如何“不起作用”的描述也会有所帮助(根本没有结果?不提取数据?等等)。
  • 此外,这里的示例数据选择不当,因为您的 Person 示例中的 ID 与 Student 或 Faculty 示例中的 ID 不一致,从而阻止任何人实际演示一个有效的查询数据。
  • 我强烈建议删除不需要将事物连接在一起的额外数据(因为它会使您的问题更长,同时不会增加任何价值)超出识别该内容所必需的最低限度,并且 添加个足以让您的问题中给出的内容实际解析的条目——使其最小完整可验证;另见stackoverflow.com/help/mcve
  • @CharlesDuffy,感谢您的建议,提供体面的 XML 数据有点困难,因为 XML 文件的结构很奇怪。我提供的尝试介于更改它以试图获得可行的东西之间。
  • 有关此查询效率的任何建议都将在很大程度上取决于您使用的 XQuery 处理器(如果您使用的是 XML 数据库,它配置了哪些索引)。当然,这也取决于数据大小。正如所写的那样,它看起来好像具有二次性能,但一个好的优化器会避免这种情况。例如:Saxon-HE 和 Saxon-EE 将在这样的连接查询上给出完全不同的结果(Saxon-EE 将建立一个索引以通过 ID 快速访问 Person 元素)。

标签: xml xquery


【解决方案1】:

更好的代码可能看起来像这样:

declare variable $students := doc("../Students.xml")/AllStudents/Student;
declare variable $faculty := doc("../Faculty.xml")/AllFaculty/Faculty;
declare variable $persons := doc("../Person.xml")/AllPersons/Person;

for $student in $students
let $faculty := $faculty[FacultyID=$student/MentorID]
let $student_person := $persons[ID=$student/StudentID]
let $faculty_person := $persons[ID=$student/MentorID]
return
  <StudentMentor>{
      $student_person/Name,
      <Mentor>{$faculty_person/Name}</Mentor>
    }</StudentMentor>

使用上面的测试数据,我得到以下输出:

<StudentMentor>
  <Name>Jinchao Henson</Name>
  <Mentor>
    <Name>Min Tuyet</Name>
  </Mentor>
</StudentMentor>
<StudentMentor>
  <Name>John Basaraba</Name>
  <Mentor>
    <Name>Richard Ellison</Name>
  </Mentor>
</StudentMentor>

注意:

  • 这里没有任何where 子句;您的查询不需要它们,并且选择大量可能的排列并使用哪里来筛选是非常低效的(或者至少是单调的),而不是直接获取您真正想要的数据。
  • 选择 所有 学生、教师或“let”中的人员是没有意义的;任何对整个查询都是全局的,而不是限定在使用“for”迭代的项目,都应该声明为变量。
  • 如果您的数据库没有被索引以能够避免递归,则将使用 // 替换为显式遍历根节点会更有效。你可以使用$students_doc/*/Student(其他人也一样)来达到类似的效果。

【讨论】:

  • 完美,但您甚至可以消除 $faculty,因为它不会在您的查询中使用,如果我没记错的话也不需要。
  • 再次感谢,非常有帮助!
  • 您可以从每个谓词内部删除./,因为它是多余的。您还可以将路径选择移出 FLOWR,这将使过程更高效,因为每次循环迭代您将拥有更少的导航,例如declare variable $persons := doc("../Person.xml")/AllPersons/Person;let $student_person := $persons[ID=$student/StudentID]let $faculty_person := $persons[ID=$student/MentorID]。您可以将该模式应用于此示例中的所有 doc() 调用
猜你喜欢
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多