XPath / XQuery - 在排除某些元素时选择节点

时间:2012-04-21 05:48:09

标签: xml xpath xquery

我有一个我需要修改的XML文件。首先,我需要进行分组,然后排除几个节点。

<cars>
    <car>
        <make>Toyota</make>
        <model>Camry</model>
        <color>White</color>
        <price>123</price>
    </car>
    <car>
        <make>Honda</make>
        <model>Accord</model>
        <color>White</color>
        <price>423</price>
    </car>
</cars>

以下是执行转换的代码:

<root>
    {
    for $color in distinct-values(doc('cars.xml')//cars/car/color)
    let $car := doc('cars.xml')//cars/car
    return  <appearance color="{$color}">
            { $car[color eq $color ] }
            </appearance>
    }
</root>

我明白了:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <appearance color="White">
        <car>
            <make>Toyota</make>
            <model>Camry</model>
            <color>White</color>
            <price>123</price>
        </car>
        <car>
            <make>Honda</make>
            <model>Accord</model>
            <color>White</color>
            <price>423</price>
        </car>
    </appearance>
</root>

除了一个问题,这需要我所需要的95%。我需要从最终的XML中排除节点“颜色”和“价格”,同时保留分组。

我尝试在return语句中执行以下操作:         {$ car [color eq $ color] / * [not(self :: price)] [not(self :: color)]}

有点工作,但它完全消除了“汽车”元素!有什么建议吗?

3 个答案:

答案 0 :(得分:5)

试试这个:

<root>
{
    let $cars-doc := doc('cars.xml')
    let $color := distinct-values($cars-doc//cars/car/color)
    return
        for $carcolor in $color
        return
            <appearance color="{$carcolor}">
            {
                for $car in $cars-doc//cars/car
                where $car/color = $carcolor
                return 
                    <car>
                    {$car/*[not(self::color or self::price)]}
                    </car>  
            }
            </appearance>
}
</root>  

希望这有帮助。

答案 1 :(得分:1)

我喜欢black sowl的解决方案,但我建议使用以下稍微清洁的代码版本。通过以下方式清洁:

  1. 不需要使用//汽车,因为汽车是根本元素
  2. 第一个返回语句是不需要的
  3. 无需反复穿越汽车/汽车
  4. 使用单数和&amp;变量名中的复数表示单项与序列

    <root>
        {
        let $cars := doc('cars.xml')//car
        let $colors := distinct-values($cars/color)
        for $color in $colors
        return
            <appearance color="{$color}">
                {
                for $car in $cars[color = $color]
                return 
                    <car>
                        {$car/*[not(self::color or self::price)]}
                    </car>  
                }
            </appearance>
        }
    </root>
    

答案 2 :(得分:0)

请注意,在XPath中,您无法创建新节点。您可以返回输入文档中已存在的节点,也可以计算计数和总计等值,但如果需要新的或修改过的节点树,则需要XSLT或XQuery。

如果您的输出与您的输入类似,只需进行少量更改,那么XSLT解决方案通常比XQuery解决方案简单得多。