xml 具有可变多条件的 XPath 查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8576651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 15:04:31  来源:igfitidea点击:

XPath query with variable multiple conditions

xmlxsltxpath

提问by swornabsent

Long-time listener, first-time caller. I'm relatively new to XPath and looked at several other threads here and elsewhere but I can't seem to get a query working, any help would be great.

长期聆听者,初次来电者。我对 XPath 比较陌生,并在此处和其他地方查看了其他几个线程,但我似乎无法使查询正常工作,任何帮助都会很棒。

I have XML as follows:

我有如下 XML:

<catalog>
  <book pgid="28054" lang="en">
    <title>The Brothers Karamazov</title>
    <author>Dostoyevsky, Fyodor</author>
    <friendly_title>The Brothers Karamazov by Fyodor Dostoyevsky</friendly_title>
    <file>
      <type>ePub</type>
      <path>cache/generated/28054/</path>
      <name>pg28054.epub</name>
      <size>800</size>
    </file>
    <file>
      <type>PDF</type>
      <path>2/8/0/5/28054/</path>
      <name>28054-pdf.pdf</name>
      <size>5829</size>
    </file>
    <file>
      <type compression="zipped">PDF</type>
      <path>2/8/0/5/28054/</path>
      <name>28054-pdf.zip</name>
      <size>1693</size>
    </file>
    <file>
      <type encoding="utf-8" compression="zipped">Text</type>
      <path>2/8/0/5/28054/</path>
      <name>28054-0.zip</name>
      <size>726</size>
    </file>
  </book>
</catalog>

(catalog is the root element, and in this example there are no <contributor>elements)

(catalog 是根元素,在这个例子中没有<contributor>元素)

I have the query working on author, contributor, title, and language searches, but I am getting hung up on adding a file type condition. This query to find books with author OR contributor containing "Dostoyevsky" and title containing "Brothers" with language "en" is working(i.e. giving expected results), but if there's a better way to write it I'm all ears:

我有关于作者、贡献者、标题和语言搜索的查询,但我在添加文件类型条件时遇到了麻烦。此查询用于查找作者或贡献者包含“陀思妥耶夫斯基”和标题包含“兄弟”且语言为“en”的书籍正在工作(即给出预期结果),但如果有更好的编写方式,我会全力以赴:

/catalog//book/*[(contains(self::author,'Dostoyevsky') or contains(self::contributor,'Dostoyevsky')) and contains(../title,'Brothers') and ../@lang = 'en']

What I can'tget to work is limiting the query results to files of a certain type, i.e. appending and ../file/type='PDF'or something. Didn't have any luck with |unions either.

无法开始工作的是将查询结果限制为某种类型的文件,即附加and ../file/type='PDF'或其他内容。|工会也没有运气。

Thanks in advance.

提前致谢。

Oh, and if it matters, the query needs to be built dynamically (from form input), so it needs to retain a universal syntax that would work with any number of user-supplied criteria.

哦,如果重要的话,查询需要动态构建(从表单输入),所以它需要保留一个通用语法,可以与任意数量的用户提供的条件一起使用。

回答by Vincent Biragnet

If I get you right, this should work :

如果我猜对了,这应该有效:

/catalog[file/type='PDF']//book/*[(contains(self::author,'Dostoyevsky') or contains(self::contributor,'Dostoyevsky')) and contains(../title,'Brothers') and ../@lang = 'en']

Note that the filter is directly on the catalogelement.

请注意,过滤器直接位于catalog元素上。

If you try to get bookelements, maybe you should use /catalog[file/type=...]//book[test1][test2][test3]...with your different constraints. Each new test act as a filter.

如果您尝试获取book元素,也许您应该使用/catalog[file/type=...]//book[test1][test2][test3]...不同的约束。每个新测试都充当过滤器。

回答by Dimitre Novatchev

This query to find books with author OR contributor containing "Dostoyevsky" and title containing "Brothers" with language "en" is working (i.e. giving expected results), but if there's a better way to write it I'm all ears:

/catalog//book/*[(contains(self::author,'Dostoyevsky') or contains(self::contributor,'Dostoyevsky')) and

contains(../title,'Brothers') and ../@lang = 'en']

此查询查找作者或贡献者包含“陀思妥耶夫斯基”和标题包含“兄弟”且语言为“en”的书籍正在工作(即给出预期结果),但如果有更好的编写方式,我会全力以赴:

/catalog//book/*[(contains(self::author,'Dostoyevsky') or contains(self::contributor,'Dostoyevsky')) and

contains(../title,'Brothers') 和 ../@lang = 'en']

The XPath expression above is not only quite imperfect and absolutely un-formatted and unreadable, but, more importantly, it doesn't (as stated) select any bookelement at all (it may select an author). Also, the //pseudo-operator isn't necessary and may significantly reduce the efficiency of XPath evaluation on any real world moderate to large XML document.

上面的 XPath 表达式不仅非常不完美,而且完全没有格式化和不可读,而且更重要的是,它根本(如所述)根本不选择任何book元素(它可能会选择一个author)。此外,//伪运算符不是必需的,并且可能会显着降低对任何现实世界中到大型 XML 文档的 XPath 评估效率。

Here is an XPath expression that selects what you want:

这是一个选择你想要的 XPath 表达式

 /catalog/book
    [@lang='en'
    and
     file/type='PDF'
    and
     *[self::author
      or
       self::contributor
       ]
        [contains(., 'Dostoyevsky')]
       and
         contains(title, 'Brothers')
     ]

Oh, and if it matters, the query needs to be built dynamically (from form input), so it needs to retain a universal syntax that would work with any number of user-supplied criteria.

哦,如果重要的话,查询需要动态构建(从表单输入),所以它需要保留一个通用语法,可以与任意数量的用户提供的条件一起使用。

This "universal syntax may look something like this:

这种“通用语法可能如下所示:

/*/book
   [
    contains(*[name() = $pName1], $pString1) 
   and
    contains(*[name() = $pName2], $pString2) 
 . . . . . .
   and
    contains(*[name() = $pNameK], $pStringK) 
    ]

where $pName1, $pName2, ..., $pNameKshould be substituted by the names of the fields the end user has specified in the search form, and

其中$pName1, $pName2, ...,$pNameK应替换为最终用户在搜索表单中指定的字段名称,并且

$pString1, $pString2, ..., $pStringKshould be substituted by the data that the user has indicated should be contained in the corresponding fields.

$pString1, $pString2, ...,$pStringK应替换为用户已指示应包含在相应字段中的数据。

回答by First Zero

A simpler way for doing this is to filter for the two/three conditions separately and join them,

一个更简单的方法是分别过滤两个/三个条件并加入它们,

<xsl:for-each select="//catalog//title[contains(., 'Dostoyevsky')] | //catalog//author[contains(., 'Brothers')]">

</xsl:for-each>

The pipe (|) will combine each result

管道 (|) 将组合每个结果