XPath / XQuery - select node, with the exception of some elements

I have an XML file that I need to modify. First I need to make a group, and then exclude a couple of nodes.

<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>

Here is my code that does the conversion:

<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>

I get:

<?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>

This is 95% of what I need, except for one problem. I need to exclude the color and price nodes from the final XML, while preserving the grouping.

I tried to do the following in my return expression: {$ car [color eq $ color] / * [not (self :: price)] [not (self :: color)]}

but he completely eliminates the element "car"! Any tips?

+3
source share
3 answers

Try the following:

<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>  

Hope this helps.

+5
source

sowl, . :

  • //, .
  • /
  • ,

    <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>
    
+1

Note that in XPath you cannot create new nodes. You can either return the nodes that already exist in the input document unchanged, or you can calculate values ​​such as counts and totals, but if you want a new or modified node tree, you need XSLT or XQuery.

If your output is similar to your input with a few changes, then the XSLT solution is often much simpler than the XQuery solution.

0
source

All Articles