XQuery循环条件

时间:2016-03-06 04:42:21

标签: xquery

我有一个遵循此DTD结构的XML文件。

<!DOCTYPE report [
<!ELEMENT report (title,section+)>
<!ELEMENT section (title,body?,section*)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT body (para+)>
<!ELEMENT para(#PCDATA)>
<!ATTLIST book version CDATA #REQUIRED>
<!ATTLIST section number ID CDATA #REQUIRED>
]>

我想使用XQuery查询以下两件事 1.获取至少出现两次的所有标题(两个标题相同的部分)。

for $x in /report/section/
for $y in /report/section/
where $x/@title = $y/@title 
return $x/@title

2。获取正文中至少10个段落或5个嵌套部分的所有部分的编号和标题。

for $x in /report/section/
where $x/para >= 10 or count(/section) > 10
return <large>$x/number $x/title</large>

但我的查询似乎不正确。我是XQuery OR XPath的初学者,有人可以告诉我如何修复我的查询吗?

编辑:示例XML

<?xml version="1.0" encoding="UTF-8"?>
<report version = '1'>
    <title>Harry Potter</title>
    <section number = '1'>
        <title>sec1</title>
        <body>
            <para>1</para>
            <para>2</para>
            <para>3</para>
            <para>4</para>
            <para>5</para>
            <para>6</para>
            <para>7</para>
            <para>8</para>
            <para>9</para>
            <para>10</para>
            <para>11</para>         
        </body>         
    </section>

    <section number = '2'>
        <title>sec2</title>
        <body><para>test</para></body>
        <section number = '2.1'>
            <title>sec21</title>
            <body>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
                <para>test</para>
            </body>
        </section>
        <section number = '2.2'>
            <title>sec21</title>
            <body><para>test</para></body>
        </section>
        <section number = '2.3'>
            <title>sec23</title>
            <body><para>test</para></body>
        </section>
        <section number = '2.4'>
            <title>sec24</title>
            <body><para>test</para></body>
        </section>
        <section number = '2.5'>
            <title>sec25</title>
            <body><para>test</para></body>
        </section>
        <section number = '2.6'>
            <title>sec1</title>
            <body><para>test</para></body>
        </section>
    </section>      
</report>

2 个答案:

答案 0 :(得分:4)

在您的第一个示例中,有两个问题。首先,您没有获得嵌套部分,因为您只是迭代作为report元素的直接子元素的section元素。其次,您在同一内容上使用两个循环。 $x$y都可以是相同的元素,因此where条件对于每个部分至少匹配一次。我会这样写:

for $x in distinct-values(/report//section/title)
    where count(/report//section[title=$x]) > 1
    return $x

循环获取所有唯一标题并循环它们(注意我们使用report//section来获取所有后代部分)。然后,对于其中的每一个,我们计算使用多少次来保持不止一次发生的次数。然后我们返回循环变量(绑定到标题)。

运行它,我们回来

sec1 sec21

在第二种情况下,我们遇到的问题是没有得到所有后代。我们还需要计算。我会用

for $x in /report//section
    where count($x/body/para) > 9 or count($x/section) > 4
    return <large>{$x/@number} {string($x/title)}</large>

请注意,我选择$x/body/para来获取该部分中的段落(它们作为body元素的子元素出现)。这会计算直接后代,但可以根据需要进行修改以获取所有后代。另请注意直接元素构造函数中使用花括号。当我们构造一个直接元素时,所有文本都是按字面读取的。花括号用于计算xquery表达式而不是文本文本。

我在标题上使用字符串函数来提取元素的文本内容。如果我们没有这样做,我们将获得一个实际的标题元素而不是其内容(这可能是一个期望的行为)。当我们提取数字属性时,它将是我们构造元素的一个属性(如果我们想要它是文本,我们可以将字符串函数应用于它)。

在这种情况下,它返回

<large number="1">sec1</large>
<large number="2">sec2</large>
<large number="2.1">sec21</large>

此处的示例使用OP提供的XML( example.xml )使用 Saxon-HE 9.7.0.2J 进行测试。只有相关部分出现在上面,但完整的第一个示例运行看起来像

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "text";
declare context item := doc("example.xml");
for $x in distinct-values(/report//section/title)
    where count(/report//section[title=$x]) > 1
    return $x

,完整的第二个例子看起来像

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "xml";
declare context item := doc("example.xml");
for $x in /report//section
    where count($x/body/para) > 9 or count($x/section) > 4
    return <large>{$x/@number} {string($x/title)}</large>

答案 1 :(得分:2)

对于XQuery 3.0中的第一个例子,我会使用

declare context item := doc("example.xml");
for $x in /report//section/title/data()
group by $x
where count($x) > 1
return $x[1]