如何在xpath中选择属于同一组的节点?
我有一个针对 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好的...我认为我们需要在您的示例中澄清一些事情 - 因为虽然它们可能看起来像小点,但实际上并非如此 - 而且,如果您遵循规则,它应该是直接的-forward 如何构造 XPath 表达式(我将展示如何构造基本 XPath 表达式的示例,同时考虑到有效模式的组,然后我的示例存在什么问题)。
让我们分步骤进行。
具有序列的组
首先,我们假设您有一个如下所示的模式:
在这种情况下,需要注意的重要一点是,我们有一个
group1
的序列,后跟group2
两者都是元素的序列。使用 sequence,(并且任何
group
元素上都没有minoccurrs='0'
属性 - 无论如何,这都是无效的,因为我会稍后解释),选择所需的元素很简单。要选择
group1
的所有元素,我们可以简单地使用以下 XPath:/root/(elem1[1]|elem2[1]|elem3)
这之所以有效,是因为我们知道生成的 XML 将始终为:
所以,没关系。我们可以始终选择第一个
elem1
、第一个elem2
和elem3
。具有选择的组
让我们假设这些组不是包含序列,而是包含选择。架构如下所示:
(这更符合您在示例中放入的架构,其中“group2 由 elem1 或 elem4 组成。”)
在这种情况下,XPath构造起来仍然很简单,因为我们知道只有两个元素,第一个元素属于
group1
,第二个元素属于group2
,如下所示:
组1
XPath 甚至更简单:/root/*[1]
独特的粒子属性
这里可能会让人感到困惑 - 我相信,你的困惑的根源就在哪里。
在你的例子中,你基本上建议使用以下架构:
此架构无效。(请注意组上添加的
maxOccurs="unbounded"
属性)。这与您的示例类似,您显示一组中出现的多个元素)。为什么?嗯,因为它会在生成的 XML 中产生潜在的歧义。
例如,我们应该如何解析以下 XML 实例:
是:
group1
,group1
,group1
,group1
group1
、group1
、group1
、group2
group1
、group1
、组2
、group1
group1
、group2
、group1
、group1
我们只是不不知道。
但 XML 模式的设计者考虑了这一点并为其制定了规则:
http://en.wikipedia.org /wiki/Unique_Particle_Attribution
并且您的假设架构违反了该规则。
现在,v1.1 确实在这方面做出了一些改进...但是,仍然存在您可以轻松创建类似歧义的情况。
在您的示例中,如果 xml 中不存在元素 3 或 4,则实际上无法判断 group1 结束位置和 group2 开始位置。
现在,如果您只想选择具有特定名称的元素,您可以轻松做到这一点:
/root/(elementName1|elementName2|elementName3)
将选择
root
下的所有元素code> 的名称为elementName1
或elementName2
或elementName3
。因此,在您的示例中,类似:
(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:
In this case, the important thing to notice is that we have a sequence of
group1
followed bygroup2
both of which are sequences of elements.With a sequence, (and no
minoccurs='0'
attribute on any of thegroup
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:
So, that's fine. We can select always the first
elem1
, firstelem2
and theelem3
.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.")
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 togroup2
, like so: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:
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:
Is that:
group1
,group1
,group1
,group1
group1
,group1
,group1
,group2
group1
,group1
,group2
,group1
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 nameselementName1
orelementName2
orelementName3
.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.