如何在xpath中选择属于同一组的节点?

发布于 2024-12-10 09:53:54 字数 4420 浏览 0 评论 0原文

我有一个针对 XML 模式有效的 XML 文档。 XML 架构具有组元素 (xs:group)。这些组由其他定义的元素组成。如何编写一个 XPath 表达式来获取指定组的所有成员?

有什么想法吗?

@Steve:

假设我的 xml 模式定义了 4 个元素(elem1、elem2、elem3、elem4)。另外,2组定义如下:

group1: (elem1 | elem2 | elem3)
group2: (elem1 | elem4)

希望你了解一些正则表达式。如果不是,则“group2: (elem1 | elem4)”仅表示 group2 由 elem1 或 elem4 组成。

我的问题是,如果我有一个 xml 文档,例如:

<elem1/>
<elem2/>
<elem3/>
<elem4/>
<elem2/>
<elem1/>
<elem3/>

如何列出该文档中属于 group1 的元素

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> 
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem0"/>
                <xs:choice minOccurs="0" maxOccurs="unbounded">
                    <xs:group ref="A1"/>
                    <xs:group ref="A2"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem0" type="xs:string"/>

    <xs:group name="A1">
        <xs:choice>
            <xs:element ref="elem10"/>
            <xs:element ref="elem11"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem10" type="xs:string"/>
    <xs:element name="elem11" type="xs:string"/>

    <xs:group name="A2">
        <xs:choice>
            <xs:element ref="elem20"/>
            <xs:element ref="elem21"/>
            <xs:element ref="elem22"/>
            <xs:element ref="elem23"/>
        </xs:choice>
    </xs:group>

    <xs:group name="CE">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem31"/>
            <xs:element ref="elem32"/>
        </xs:choice>
    </xs:group>

    <xs:group name="E">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem40"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem20">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem21">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="2" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem22">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:group ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem23">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:element ref="elem40"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required" type="xs:NMTOKEN"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem31">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="0" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem32">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="CE"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem30">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem40">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

I have an XML document which is valid against an XML schema. The XML schema has group elements (xs:group). These groups are composed of other defined elements. How can I write an XPath expression which will give me all the members of a specified group?

Any ideas?

@Steve:

assume that my xml schema has defined 4 elements (elem1, elem2, elem3, elem4). in addition, 2 groups are defined as follows:

group1: (elem1 | elem2 | elem3)
group2: (elem1 | elem4)

I hope you know some regular expressions. if no, then 'group2: (elem1 | elem4)' simply means group2 consists of EITHER an elem1 OR an elem4.

My question is if I have an xml document like:

<elem1/>
<elem2/>
<elem3/>
<elem4/>
<elem2/>
<elem1/>
<elem3/>

How can I list the elements in that document which belong to, say, group1

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> 
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem0"/>
                <xs:choice minOccurs="0" maxOccurs="unbounded">
                    <xs:group ref="A1"/>
                    <xs:group ref="A2"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem0" type="xs:string"/>

    <xs:group name="A1">
        <xs:choice>
            <xs:element ref="elem10"/>
            <xs:element ref="elem11"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem10" type="xs:string"/>
    <xs:element name="elem11" type="xs:string"/>

    <xs:group name="A2">
        <xs:choice>
            <xs:element ref="elem20"/>
            <xs:element ref="elem21"/>
            <xs:element ref="elem22"/>
            <xs:element ref="elem23"/>
        </xs:choice>
    </xs:group>

    <xs:group name="CE">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem31"/>
            <xs:element ref="elem32"/>
        </xs:choice>
    </xs:group>

    <xs:group name="E">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem40"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem20">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem21">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="2" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem22">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:group ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem23">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:element ref="elem40"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required" type="xs:NMTOKEN"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem31">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="0" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem32">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="CE"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem30">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem40">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡莣 2024-12-17 09:53:54

好的...我认为我们需要在您的示例中澄清一些事情 - 因为虽然它们可能看起来像小点,但实际上并非如此 - 而且,如果您遵循规则,它应该是直接的-forward 如何构造 XPath 表达式(我将展示如何构造基本 XPath 表达式的示例,同时考虑到有效模式的组,然后我的示例存在什么问题)。

让我们分步骤进行。

具有序列的组

首先,我们假设您有一个如下所示的模式:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:sequence>
    </xs:group>
    <xs:group name="group2">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:sequence>
    </xs:group>
</xs:schema>

在这种情况下,需要注意的重要一点是,我们有一个 group1序列,后跟group2 两者都是元素的序列

使用 sequence,(并且任何 group 元素上都没有 minoccurrs='0' 属性 - 无论如何,这都是无效的,因为我会稍后解释),选择所需的元素很简单。

要选择 group1 的所有元素,我们可以简单地使用以下 XPath:

/root/(elem1[1]|elem2[1]|elem3)

这之所以有效,是因为我们知道生成的 XML 将始终为:

<root>
     <elem1 />
     <elem2 />
     <elem3 />
     <elem1 />
     <elem2 />
</root>

所以,没关系。我们可以始终选择第一个 elem1、第一个 elem2elem3

具有选择的组

让我们假设这些组不是包含序列,而是包含选择。架构如下所示:

(这更符合您在示例中放入的架构,其中“group2 由 elem1 或 elem4 组成。”)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

在这种情况下,XPath构造起来仍然很简单,因为我们知道只有两个元素,第一个元素属于 group1,第二个元素属于 group2,如下所示

<root>
     <elem2 />
     <elem1 />
</root>

组1 XPath 甚至更简单:

/root/*[1]

独特的粒子属性

这里可能会让人感到困惑 - 我相信,你的困惑的根源就在哪里。

在你的例子中,你基本上建议使用以下架构:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1" maxOccurs="unbounded"/>
                <xs:group ref="group2" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

此架构无效。(请注意组上添加的 maxOccurs="unbounded" 属性)。这与您的示例类似,您显示一组中出现的多个元素)。

为什么?嗯,因为它会在生成的 XML 中产生潜在的歧义。

例如,我们应该如何解析以下 XML 实例:

<root>
     <elem2 />
     <elem1 />
     <elem1 />
     <elem2 />
</root>

是:

  • group1, group1, group1, group1
  • group1group1group1group2
  • group1group1组2group1
  • group1group2group1group1
  • ...

我们只是不不知道。

但 XML 模式的设计者考虑了这一点并为其制定了规则:

http://en.wikipedia.org /wiki/Unique_Particle_Attribution

并且您的假设架构违反了该规则。

现在,v1.1 确实在这方面做出了一些改进...但是,仍然存在您可以轻松创建类似歧义的情况。

在您的示例中,如果 xml 中不存在元素 3 或 4,则实际上无法判断 group1 结束位置和 group2 开始位置。

现在,如果您只想选择具有特定名称的元素,您可以轻松做到这一点:

/root/(elementName1|elementName2|elementName3)

将选择 root 下的所有元素code> 的名称为 elementName1elementName2elementName3

因此,在您的示例中,类似: (elem1|elem2|elem3) 就可以了。

但是,这不是你问的。您询问的是关于按组选择的问题 - 您提供的示例无法为您提供按组选择的真正答案。

如果您有真实有效架构,并且需要构建 XPath 的帮助,请粘贴架构,我将很乐意为您提供帮助帮助。

OK... there are a few things I think we need to clarify in your example - because, while they may seem like small points, in reality they aren't - and, if you're following the rules, it should be straight-forward how to construct the XPath expression (I'll show examples of how to construct basic XPath expressions taking groups into account for valid schemas, then what the problem I have with your example is).

Let's take it in steps.

Groups with Sequences

First, let's assume that you have a schema which looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:sequence>
    </xs:group>
    <xs:group name="group2">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:sequence>
    </xs:group>
</xs:schema>

In this case, the important thing to notice is that we have a sequence of group1 followed by group2 both of which are sequences of elements.

With a sequence, (and no minoccurs='0' attribute on any of the group elements - which would be invalid anyways as I'll explain later), selecting the required elements is trivial.

To select all elements of group1 we might simply use the following XPath:

/root/(elem1[1]|elem2[1]|elem3)

This works because we know the resulting XML will always be:

<root>
     <elem1 />
     <elem2 />
     <elem3 />
     <elem1 />
     <elem2 />
</root>

So, that's fine. We can select always the first elem1, first elem2 and the elem3.

Groups with Choices

Lets assume that instead of those groups containing sequences, that instead they contained choices. With the schema looking like this:

(This is more along the lines of the schema you put in your example, where "group2 consists of EITHER an elem1 OR an elem4.")

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

In this case, the XPath is still trivial to construct, because we know there will only be two elements, and the first will belong to group1 and the second will belong to group2, like so:

<root>
     <elem2 />
     <elem1 />
</root>

So the group1 XPath is even simpler:

/root/*[1]

Unique Particle Attribution

Here is where it might get confusing - and where, I believe, the source of your confusion comes in.

In your example, you basically have suggested the following schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1" maxOccurs="unbounded"/>
                <xs:group ref="group2" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

This schema is invalid. (Notice the addition of the maxOccurs="unbounded" attribute on the groups). This is similar to your example where you show multiple elements from one group occurring).

Why? Well, because it creates a potential ambiguity in the resulting XML.

For example, how should we parse the following XML instance:

<root>
     <elem2 />
     <elem1 />
     <elem1 />
     <elem2 />
</root>

Is that:

  • group1, group1, group1, group1
  • or group1, group1, group1, group2
  • or group1, group1, group2, group1
  • or group1, group2, group1, group1
  • ...

We just don't know.

But the designers of XML Schemas thought about that and made a rule for it:

http://en.wikipedia.org/wiki/Unique_Particle_Attribution

And your hypothetical schema violates that rule.

Now, v1.1 does make some improvements in this area... however, there are still situations where you can easily create similar ambiguities.

In your example, if no elements 3 or 4 are present in the xml, it's really quite impossible to tell where group1 ends and group2 begins.

Now, if all you want to do is select elements with a particular name, you can do that easily:

/root/(elementName1|elementName2|elementName3)

would select all elements under root with the names elementName1 or elementName2 or elementName3.

So, in your example, something like: (elem1|elem2|elem3) would be just fine.

But, that's not what you asked. What you asked was about selecting by group - and the example you provided made it impossible to give you a real answer for by group.

If you have a real, valid schema, and you need help constructing the XPath, please paste that schema, and I'll be happy to help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文