Edgewall Software

Opened 17 years ago

Last modified 5 years ago

#81 new defect

local-name() doesn't work with attributes

Reported by: dackze+genshi@… Owned by: cmlenz
Priority: major Milestone:
Component: XPath support Version: devel
Keywords: Cc: james.harris@…, remy.blank@…

Description

Given:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/">
  <foo py:match="foo">
    ${select('@*[local-name() = "c"]')}
  </foo>

  <foo a="1" b="2" c="3" />
</html>

The following is produced:

<html xmlns="http://www.w3.org/1999/xhtml">
  <foo>
  </foo>
</html>

But you'd expect:

<html xmlns="http://www.w3.org/1999/xhtml">
  <foo>
    3
  </foo>
</html>

select('@*[local-name() = "c"]') should be equivalent to select('@c').

Attachments (1)

xpath.patch (22.2 KB) - added by Carsten Klein <carsten.klein@…> 14 years ago.
Work in progress, just for review and comment

Download all attachments as: .zip

Change History (10)

comment:1 Changed 17 years ago by dackze+genshi@…

Here's a simpler test case:

from genshi.template import MarkupTemplate
a = list(MarkupTemplate('<z a="1" />').generate().select('@*[local-name() = "a"]'))
b = list(MarkupTemplate('<z a="1" />').generate().select('@a'))
assert a == b

comment:2 Changed 17 years ago by cmlenz

Oops, predicates don't take the axis of the node test into account :-P

Thanks for reporting this, I'll look into it.

comment:3 Changed 17 years ago by cmlenz

  • Milestone changed from 0.4 to 0.5

Not for 0.4, sorry.

comment:4 Changed 16 years ago by anonymous

  • Cc james.harris@… added

comment:5 Changed 16 years ago by cmlenz

  • Milestone 0.5 deleted

This one's going to be tricky… postponing so some future version.

comment:6 Changed 16 years ago by anonymous

This bug is very important, because there is no way to exclude an attribute from an attribute list in a match template.

Maybe you should use the XPATH 2.0 exclude operator for this purpose.

comment:7 Changed 14 years ago by Carsten Klein <carsten.klein@…>

I am currently working on this. Here is an initial, still incomplete proposal for a patch.

Currently the OP's original testcase will work.

The testcase in comment1 I consider invalid since the @* attribute axis selected is actually empty, see xpath spec. since we do not have a context element here. In the original testcase the context element is foo since that is being matched.

I also added the named axis parameter to the functions, but I think that this is redundant and can be omitted.

The operators definitely need additional work.

I am posting this here, so you can also have a look at it, perhaps providing additional information a/o continuing work on the patch.

comment:8 Changed 14 years ago by Carsten Klein <carsten.klein@…>

Testcase I am using is:

from genshi.template import MarkupTemplate
tpl = MarkupTemplate("""
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/">
  <foo py:match="foo">
    ${select('@*[local-name() = "c" or local-name() = "b"]')}
  </foo>

  <foo a="1" b="2" c="3" />
</html>
""")
list(tpl.generate())

And the output (stream) is as follows:

[('START_NS', ('', u'http://www.w3.org/1999/xhtml'), (None, 2, 0)), ('START', (QName('http://www.w3.org/1999/xhtml}html'), Attrs()), (None, 2, 0)), ('TEXT', u'\n  ', (None, 3, -1)), ('TEXT', u'\n\n  ', (None, 6, -1)), ('START', (QName('http://www.w3.org/1999/xhtml}foo'), Attrs()), (None, 4, 2)), ('TEXT', u'\n    ', (None, 4, -1)), ('TEXT', u'32', (None, -1, -1)), ('TEXT', u'\n  ', (None, 5, 57)), ('END', QName('http://www.w3.org/1999/xhtml}foo'), (None, 6, 2)), ('TEXT', u'\n', (None, 9, -1)), ('END', QName('http://www.w3.org/1999/xhtml}html'), (None, 9, 0)), ('END_NS', '', (None, 9, 0))]

As you can see, both attribute c and b are being selected and their values appear in the stream as ('TEXT', u'32', (None, -1, -1)).

IMPORTANT: The patch is considered work in progress and definitely breaks existing functionality, i.e. previously working templates will no longer work.

Changed 14 years ago by Carsten Klein <carsten.klein@…>

Work in progress, just for review and comment

comment:9 Changed 13 years ago by rblank

  • Cc remy.blank@… added

I stumbled upon this issue while trying to replace the value of an attribute in an element with a py:match:

<textarea py:match="form[@id='propertyform']//textarea[@id='comment']"
          py:attrs="select('@*[local-name()!=\'rows\']')" rows="20">
  ${select('*|comment()|text()')}
</textarea>

Is there another way to replace the value of a single attribute of an element than to copy the whole element except the attribute, and adding the new attribute?

Note: See TracTickets for help on using tickets.