Edgewall Software

Ticket #81 (new defect)

Opened 8 years ago

Last modified 13 months ago

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

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

Change History

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

Changed 8 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.

Changed 8 years ago by cmlenz

  • milestone changed from 0.4 to 0.5

Not for 0.4, sorry.

Changed 7 years ago by anonymous

  • cc james.harris@… added

Changed 7 years ago by cmlenz

  • milestone 0.5 deleted

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

Changed 6 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.

Changed 5 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.

Changed 5 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 5 years ago by Carsten Klein <carsten.klein@…>

Work in progress, just for review and comment

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

Add/Change #81 (local-name() doesn't work with attributes)

Author


E-mail address and user name can be saved in the Preferences.


Change Properties
<Author field>
Action
as new
as The resolution will be set. Next status will be 'closed'
to The owner will change from cmlenz. Next status will be 'new'
The owner will change from cmlenz to anonymous. Next status will be 'assigned'
 
Note: See TracTickets for help on using tickets.