2

我有一系列变量类型,例如:

abc1A, abc1B, abc3B, ...
xyz1A, xyz2A, xyz3C, ...
data1C, data2A, ...

以多种xml格式存储:

<area name="DataMap">
    <int name="number" nullable="true">
        <case var="abc2,abc3,abc5">11</case>
        <case var="abc4,abc6*">8</case>
        <case var="data1,xyz7,xyz8">22</case>
        <case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case>
        <case var="xyz{6,4A,4B,4C}">20</case>
        <case var="other01">15</case>
    </int>
</area>

我希望查询像 xyz5A 这样的实例映射到什么。查询应该返回 24,但我不知道它在 xml 节点中的引用是否像“xyz4A”那样显式,或者通过像“xyz4*”这样的通配符,或者像上面那样在花括号中。

这会查询该行上的字符串并将成功返回命中:

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"xyz")][contains(@var,"5A")]'

但它也返回一个不正确的 data5A 命中:

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"data")][contains(@var,"5A")]'

是否存在解析上述不一致(但我认为是有效的)xml 的 xpath/其他查询构造?我似乎只能查询显式字符串匹配与通配符和花括号格式。

4

2 回答 2

1

身在其中,bash/perl你很可能必然会libxml。libxml 不支持 XPath 2.0。关于带有 libxml/libxslt 和 Perl 的 XPath/XSLT 2.0 有很多关于 SO 的问题。

XPath 1.0 有多种字符串函数(我不得不承认其中很小),您可以尝试将它们堆叠在一起。我进行了一些实验,结果我也不喜欢,也没有成功涵盖所有可能的情况。你会有“丑陋”的结构,如:

...
or
(contains(@var, ',xyz{') and 
 contains(substring-before(substring-after(@var, ',xyz{'), '}'), '5A') and
     (contains(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A,') or
      starts-with(substring-after(@var, ',xyz{'), '5A,') or
      starts-with(substring-after(@var, ',xyz{'), '5A}') or
      substring-after(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A') = ''))

or
...

然后你会意识到substring-*函数在匹配字符串的第一次出现时起作用,你需要更多的ands 和ors 层来处理像你这样的情况:

<case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case>

哪里有多个xyz{,而您需要的一个不知道是第一个。

我认为这是您忘记了自己拥有 XML 并只做 Perl 擅长的事情并将其视为文本的情况。尽管我很喜欢用于 XML 处理和数据提取的 XML 感知工具,但您可能会更好地使用专为它设计的语言中的正则表达式和字符串操作。

于 2012-05-18T15:34:26.957 回答
0

我想最聪明的做法是遍历所有变量并以编程方式找到匹配项,而不是要求 XPath 去做。

除此之外,我至少对牙套有一些想法;不幸的是,他们可能对这个问题没有太大帮助*

似乎有 perl XPath 实现,您可以在其中编写.../case[@var =~ /some_regex/],也许.../case["xyz4A" =~ to_regex(@var)],甚至可能.../case[explode_braces(@var) =~ /(^|,)xyz4A(,|$)/](当然,使用适当编写explode_braces的函数)。例如,参见http://www.perlmonks.org/?node_id=831612 。我希望这种explode_braces方法比第一种方法更容易工作——而且我确实经常使用正则表达式。再说一次,您似乎使用了 bash-regex,并且将它们转换为 perl 正则表达式也应该相对简单,所以如果第二个想法有效,那么您可能会很高兴。

如果这不起作用,也许挂钩到您的 XML 解析器或在它之前并通过扩展大括号来修复这个可怕的 XML 设计?

$input =~ s/\bvar="([^"]*)"}/'var="'+explode_braces($2)+'"'/eg;

(或者非常相似的东西,对不起,我在过去几年没有写太多 perl。另外,这假设你的 xml 只使用一种类型的属性引号,但这应该很容易修复,并且是唯一var="可以找到的地方是在这些属性中,这可能是一个更难的限制。)

于 2012-05-18T18:17:59.697 回答