-
Notifications
You must be signed in to change notification settings - Fork 31
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
Keep track of attribute namespaces #33
base: master
Are you sure you want to change the base?
Conversation
src/lib.rs
Outdated
trait ToAttributeMaps { | ||
fn to_attribute_maps(self) -> (AttributeMap<String, String>, AttributeMap<String, Namespace>); | ||
} | ||
|
||
impl ToAttributeMaps for Vec<xml::attribute::OwnedAttribute> { | ||
fn to_attribute_maps(self) -> (AttributeMap<String, String>, AttributeMap<String, Namespace>) { | ||
let mut attr_map = AttributeMap::with_capacity(self.len()); | ||
let mut attr_map_ns = AttributeMap::new(); | ||
|
||
for attr in self { | ||
if let Some(ns) = attr.name.prefix { | ||
let xns = Namespace::from_iter([(ns, attr.name.namespace.unwrap_or(xml::namespace::NS_EMPTY_URI.to_string()))]); | ||
attr_map_ns.insert(attr.name.local_name.clone(), xns); | ||
} | ||
attr_map.insert(attr.name.local_name, attr.value); | ||
} | ||
|
||
(attr_map, attr_map_ns) | ||
} | ||
} | ||
|
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.
This is the important bit, most of the rest is tests/boilerplate to try to keep as much compatibility with the old non-newtype xmltree::Namespace
as Rust will let us have.
The changes just pushed (9216575 – 8972930) improve code quality a tad, but don't change function or test results.
|
/// ```xml | ||
/// <mdui:DisplayName xml:lang="en">TestShib Test IdP</mdui:DisplayName> | ||
/// ``` | ||
pub attribute_namespaces: AttributeMap<String, Namespace>, |
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 a better API would be to add a new Attribute
struct similar to the Element
struct
pub struct Attribute {
pub name: String,
pub namespace: Option<String>,
pub prefix Option<String>,
}
and have that be stored in Element::attributes
.
IIRC attributes can also be provided multiple times, so maybe Element::attributes
should just be a Vec
of such structs, and the struct should also include the attribute value.
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.
And one could also add a getter function that works on predicates and finds the corresponding attribute.
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 underlying xml library will never give us the same attribute/ns combo with the same value twice.
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.
Hello, I hope you don't mind me chiming in on this PR but I also have need of this feature. Unfortunately the PR as it currently stands doesn't work for my use case, which is where I have two attributes with the same name but different namespaces, e.g.
<tag attribute="foo" extended:attribute="bar"/>
So Sebastian's suggestion seems like a good one, although it sounds like it would break backward compatibility if it changed the current Element::attributes
member.
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.
Uh, does that happen even in the case of:
<tag a:b="A" b:b="B"/>
?
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.
Okay I see what's wrong. You're right @tombailo that @sdroege made a good suggestion. My not acting on it wasn't a judgment on the quality of the suggestion, my lack of action was just due to the fact the main struggle in this PR is keeping backwards compatibility, which I didn't even manage fully.
I'm going to think some more on the problem and see if I can't find some happy medium between a total API break and my broken implementation. Thanks for testing my PR!
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.
You're welcome!
Regarding API compatibility, I can't really see how to see how to fix this without a breaking change. It's an unarguable fact that attribute names can be namespace-qualified and that names in different namespaces need to be discriminated. One option could be to use the namespace-qualified name in attributes
, but that would be inconsistent with the rest of the Element
API where names and namespaces are broken out and handled separately. So to me it looks like an API change is inevitable, but I have no idea how big a deal that would be.
Of course ultimately it's up to the maintainers, and I'm pretty new to Rust development, but that's my 2 cents for what it's worth.
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'm considering storing both by default with a compile-time flag to disable the duplication. Thoughts?
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.
That would keep current users of the library happy, but would have a couple of downsides. One is some increased complexity in the code and tests, which would have to be maintained going forward. The other is that the current API and implementation could be causing bugs for current users of the library, which they just haven't found yet. If I'm parsing XML which looks like <tag ns1:attr="foo" ns2:attr="bar"/>
and I only care about ns2:attr
, my application will work fine until it receives XML with the attributes reversed, i.e. <tag ns2:attr="bar" ns1:attr="foo"/>
.
So to me that's an argument for making a breaking change and forcing current users to make the (relatively simple) changes update their code.
But, like I say, it's not my project, and I'm pretty new to the world of Rust.
Perhaps a pragmatic way to proceed would be to put the change up for review without any compile-time backwards compatibility feature flag, and if the maintainers request such a feature flag, you can always add it.
Hope this helps and thanks for trying to fix 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.
Thanks for the thoughts. I agree with you and will make a semver breaking change. It's up to @eminence whether to pull it or not. :-)
@eminence Don't merge until reading discussion above about two attributes w/same name from different namespaces. I didn't consider this case and more radical change is needed to handle it but since you were occupied with other matters didn't try to architect something as it's gonna have to be semver breaking. |
Thanks for the heads up |
Closes #13.