0

I am working with the shopify item feed xml which has items and image separated. I'd like to get an item's image url with a single xpath. The xml looks something like this-

<products>
    <product>
        <variants>
            <variant>
                <image-id>123</image-id>
            </variant>
        </variants>
    </product>
    <images>
        <image>
            <id>123</id>
            <src>https://abc/</src>
        </image>
    </images>
</products>

My starting point is within the variant. So to get to the image I can go up two parents, down into images, fetch the image with the matching id, then get the src from that element.

parent::*/parent::*/images/image[id/text()="123"]/src/text()

This works, but it's hard coded to "123". What i'd like is to take the image-id text from the variant and use that as the predicate value.

parent::*/parent::*/images/image[id/text()=image-id/text()]/src/text()

XPath at least doesn't complain about this, but it doesn't work as I was hoping. Is it possible to use the value from image-id/text() as the predicate value for id/text()= ?

1
  • ./../../images/image[id = ./../../product/variants/variant/image-id]/src/text() Commented Oct 10, 2020 at 0:53

2 Answers 2

1

Your original approach doesn't work because of the predicate [id/text()=image-id/text()]. Predicates are evaluated in the context of the node they refer to, so in case of image[id/text()=image-id/text()] you'd assume that image also has a child node image-id which you compare with id. As far as my understanding of XPath goes, this isn't solvable with XPath alone since the context of variant/image-id has to be remembered somehow.

You could achieve this by storing your variant/image-id in a variable within your loop and use this for selecting the correct image.

Example in XQuery:

for $variant in //variant return
  let $image-id := $variant/image-id
  return
    $variant//ancestor::products//image[id = $image-id]
Sign up to request clarification or add additional context in comments.

4 Comments

This confirms what I was expecting- that this simply isn't possible in XPath. To get around this I ended up creating a custom function (using python lxml)
@micah - see my comment under your question. It possible with xpath. It works.
@AlexanderPetrov Sure, your solution works well and doesn't store the context of the variant, but selects it anew. I think it is a feasible solution for the example provided, but might lead to other problems when we have more than one product with more than one variant–then we would have to know the exact position of the variant or create an even longer XPath. Storing the context comes in handier for programming, I think. Or am I overlooking something here?
Yes, we need to store the context one way or another. In real code, I would not do everything in xpath, but would store intermediate values in variables of a some programming language.
0

If I understand you correctly, the following expression should work:

//images/image[id=//variant/image-id]/src/text()

Output:

https://abc/

3 Comments

I probably asked my question wrong. I am looping over the variants and fetching the image from within that variants context. so it would have to use the current context's //images/image[id=./image-id/text()]/src/text() - but this doesn't work because ./ appears to be the image...
.//image-id/text() doesn't work either. very strange
I'm afraid I don't understand - what does "work" mean here?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.