我有一个XML如下:
<object>
<codes>
<cd1>A</cd1>
<cd2>B</cd2>
<cd3>C</cd3>
</codes>
<codes>
<cd1>A</cd1>
<cd2>D</cd2>
<cd3></cd3>
</codes>
<codes>
<cd1>E</cd1>
<cd2>D</cd2>
<cd3></cd3>
</codes>
</object>
到目前为止,我的XPath演变如下:
-
//cd1|//cd2|//cd3
:获取所有cd1,cd2和cd3元素 -
(//cd1|//cd2|//cd3)[text()[1]]
:从上面的列表中过滤所有具有非空文本值的元素,并返回以下元素 .
<cd1>A</cd1> <cd2>B</cd2> <cd3>C</cd3> <cd1>A</cd1> <cd2>D</cd2> <cd1>E</cd1> <cd2>D</cd2>
- 现在我需要删除具有重复文本值的元素 . 我试过xpath为
(//cd1|//cd2|//cd3)[text()[1]][(preceding::cd1)|(preceding::cd2)|(preceding::cd3)]
. 我希望实现的是检查值是否在上面的任何cd1或cd2或cd3之前 . 但是这会在<cd2>D</cd2>
重复的地方返回 .
<cd2>B</cd2> <cd3>C</cd3> <cd1>A</cd1> <cd2>D</cd2> <cd1>E</cd1> <cd2>D</cd2>
我怎样才能编写一个xpath来解决上面的问题(3)?
请注意我必须使用Xpath 1.0,因此不能使用distinct-values函数 . 此外,我需要获取匹配的节点列表,而不是xpath中的文本值,因为我必须使用AXIOM在这些节点上进行更多处理 .
更新:我正在使用此xpath来获取匹配的元素,然后使用AXIOM进行处理 . 因此,我需要编写一个单独的xpath表达式来一次性获取匹配元素(我无法在AXIOM中编写自定义流或使用XSLT) . 另外cd *也不能使用,因为实名不匹配 . 我在这里使用了一个样本 .
3 回答
试试这个:
这实际上是非常简单的Muenchian分组,只有三个键:
输出:
或者,如果要对它们进行分组而不管节点名称(即
cd1
和cd2
都将A
作为文本值),那么它就不那么简单了 .这将提供与上面相同的输出(但按当前模板输出的方式排序),但会消除共享相同文本的
cd1
,cd2
或cd3
之间的重复(并且只取第一个具有它的文本) .另请注意,我忽略了空节点 - 可能不需要(并且可以通过从选择器中删除
./text() != ''
来轻松修复 - 但是,如果需要,可能必须使用不同的方法来消除重复的空节点(可能只是一系列模板或xsl:if
s测试空节点并输出单个节点(如果有的话) .我发现的一种方法是使用以下模板:
这将获取所有cd *元素,并获取每个元素的内容,它使用它来计算前面有多少相同内容 - 如果那是0 - >然后它使用它 .
据我所知,这是在xslt-1中完成的唯一方法(通过使用变量) . 这是因为你不能在xpath中反向引用 - 除非你在变量中有值(并且你需要将“当前”(外部)文本与“当前”(xpath中的节点)文本进行比较) .
希望这可以帮助 .