-
Notifications
You must be signed in to change notification settings - Fork 266
Make NamespaceResolver public
#893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@faassen want to do a review? |
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #893 +/- ##
==========================================
+ Coverage 55.52% 58.17% +2.64%
==========================================
Files 42 42
Lines 15511 15231 -280
==========================================
+ Hits 8613 8860 +247
+ Misses 6898 6371 -527
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c1bf733 to
73c66f8
Compare
faassen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the main blocker for my use cases is a way to push my own namespace bindings without having to construct a BytesStart.
I wanted to mention this use case in addition:
In my codebase I have both OwnedPrefixDeclaration and OwnedNamespace. Their primary use case is to be able to create and store this kind of stuff in configuration for the various operations I need to do over them. So, I need to be able to create them independently from events. Perhaps I overlooked a way to do owned versions of PrefixDeclaration and Namespace themselves.
I'll also note that my OwnedPrefixDeclaration stores the whole xmlns:foo bit, rather than just the prefix like PrefixDeclaration does, because otherwise I need to do allocation each time I want to turn it into a QName, which I want to do when I want to construct an namespace declaration XML attribute from it. Note that this doing this without allocation is a use case not currently supported by quick_xml's PrefixDeclaration either, afaik.
src/events/attributes.rs
Outdated
| self.any(|attr| { | ||
| if let Ok(attr) = attr { | ||
| match reader.resolve_attribute(attr.key) { | ||
| match resolver.resolve(attr.key, true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nice if the resolver gained resolve_element and resolve_attribute as convenience APIs too, mirroring what's on BytesStart.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, will add
| /// | ||
| /// [namespace binding]: https://www.w3.org/TR/xml-names11/#dt-NSDecl | ||
| /// [namespace bindings]: https://www.w3.org/TR/xml-names11/#dt-NSDecl | ||
| pub fn push(&mut self, start: &BytesStart) -> Result<(), NamespaceError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In c14n I have a use case where I want to filter through the actually utilized namespace declarations and selectively add them on a namespace resolver I manage (and also use the one for the NsReader).
So I'm looking for an API where I can add PrefixDeclaration directly.
I expected a new for NamespaceResolver resolver but there is only a Default. Should we add a new too that calls default? In addition to that I'd like to be able to pass some "top-level" bindings in when I construct the resolver, but I think doing a push immediately after construction should be sufficient to do this, as its nesting level is independent from that of the document anyway as far as I can tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you would like to have this lines extracted into the new add(PrefixDeclaration, Namespace) method?
Lines 547 to 591 in 73c66f8
| match k.as_namespace_binding() { | |
| Some(PrefixDeclaration::Default) => { | |
| let start = self.buffer.len(); | |
| self.buffer.extend_from_slice(&v); | |
| self.bindings.push(NamespaceBinding { | |
| start, | |
| prefix_len: 0, | |
| value_len: v.len(), | |
| level, | |
| }); | |
| } | |
| Some(PrefixDeclaration::Named(b"xml")) => { | |
| if Namespace(&v) != RESERVED_NAMESPACE_XML.1 { | |
| // error, `xml` prefix explicitly set to different value | |
| return Err(NamespaceError::InvalidXmlPrefixBind(v.to_vec())); | |
| } | |
| // don't add another NamespaceEntry for the `xml` namespace prefix | |
| } | |
| Some(PrefixDeclaration::Named(b"xmlns")) => { | |
| // error, `xmlns` prefix explicitly set | |
| return Err(NamespaceError::InvalidXmlnsPrefixBind(v.to_vec())); | |
| } | |
| Some(PrefixDeclaration::Named(prefix)) => { | |
| let ns = Namespace(&v); | |
| if ns == RESERVED_NAMESPACE_XML.1 { | |
| // error, non-`xml` prefix set to xml uri | |
| return Err(NamespaceError::InvalidPrefixForXml(prefix.to_vec())); | |
| } else if ns == RESERVED_NAMESPACE_XMLNS.1 { | |
| // error, non-`xmlns` prefix set to xmlns uri | |
| return Err(NamespaceError::InvalidPrefixForXmlns(prefix.to_vec())); | |
| } | |
| let start = self.buffer.len(); | |
| self.buffer.extend_from_slice(prefix); | |
| self.buffer.extend_from_slice(&v); | |
| self.bindings.push(NamespaceBinding { | |
| start, | |
| prefix_len: prefix.len(), | |
| value_len: v.len(), | |
| level, | |
| }); | |
| } | |
| None => {} | |
| } |
I doesn't add new because there is already default, but calling that requires that Default trait was in scope. So maybe the new method has the right to life. Actually, I would like to see it constant (which is impossible for trait method implementations yet).
| /// [`Empty`]: Event::Empty | ||
| /// [`Start`]: Event::Start | ||
| /// [`End`]: Event::End | ||
| pub fn resolve_event<'i>(&self, event: Event<'i>) -> (ResolveResult<'_>, Event<'i>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One operation I use is this:
is_declared (given a prefix declaration and namespace, return a boolean if it's declared. this also needs to understand undeclarations, I think quick_xml supports namespaces 1.1 so I think anything could be undeclared?)
I can build this myself but I'm mentioning it in case we want to add this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably .bindings().any() is enough for this?
I think quick_xml supports namespaces 1.1 so I think anything could be undeclared?
Yes, we support 1.1, but I also want to support 1.0 rules, because when XML declaration defined 1.0 document, we 1.1 parser should apply 1.0 rules.
xmlns and xml prefixes cannot be undeclared, it is an error to do that (that is follow from forbidding of they redeclaration with another namespace)
| use Event::*; | ||
|
|
||
| match event { | ||
| Empty(e) => (self.resolve_prefix(e.name().prefix(), true), Empty(e)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a minor comment, but initially I responded with, but I need resolve_prefix in the public API! But now I realize it's already exposed indirectly through resolve. Perhaps this code can use resolve rather than resolve_prefix, or we could even merge the two into one - always use the "attribute" bool rather than introduce a use_default concept where the boolean needs to be flipped. (even though the use_default concept is fine by itself).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the attribute parameter, because that is what using by the NsReader methods, and I want to be consistent here. But if make resolve_prefix public, we can return to the use_default conception
src/reader/ns_reader.rs
Outdated
| #[inline] | ||
| pub fn resolve_element<'n>(&self, name: QName<'n>) -> (ResolveResult<'_>, LocalName<'n>) { | ||
| self.ns_resolver.resolve(name, true) | ||
| self.ns_resolver.resolve(name, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The flipping of true to false in this PR in quite a few places is basically because we're not using a single resolve_prefix API with a consistent meaning for the boolean.
…NamespaceResolver`
…f defined bindings on each level
73c66f8 to
63e192b
Compare
63e192b to
b12ef9f
Compare
This introduces small breaking change --
Attributes::has_nilnow accepts&NamespaceResolverinstead ofReader<R>and does not need to be generic anymore (which is good).Other changes that may look as breaking in the diff not breaking changes, because they was made on initially private types.