Skip to content
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

NamespaceManager.bind(prefix, namespace, replace=True) leaves existing prefix in place #543

Closed
Jeroen537 opened this issue Nov 12, 2015 · 5 comments
Labels
bug Something isn't working enhancement New feature or request fix-in-progress
Milestone

Comments

@Jeroen537
Copy link

I want to change an existing and bound namespace prefix. From the documentation of NamespaceManager I understand that "bind" with parameter "replace=True" should achieve this. However, while this does associate the namespace with the new prefix, the old prefix remains bound to the same namespace.
This can make it impossible to obtain a serialization with the new prefix. Is this intended behaviour?

Code example:

from rdflib import Graph, Namespace

g = Graph()

g.parse(data="""<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
   xmlns:ns1="http://somewhere/else#"
   xmlns:ns2="http://nowhere/else#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
>
  <rdf:Description rdf:about="http://somewhere/else#y">
    <ns2:Q rdf:resource="http://somewhere/else#z"/>
  </rdf:Description>
  <rdf:Description rdf:about="http://somewhere/else#root">
    <ns1:P rdf:resource="http://somewhere/else#y"/>
    <ns1:P rdf:resource="http://somewhere/else#x"/>
  </rdf:Description>
</rdf:RDF>
""")

for ns in g.namespaces():
    print('%s (%s)' % (ns))

# prints:
#
# xml (http://www.w3.org/XML/1998/namespace)
# ns2 (http://nowhere/else#)
# ns1 (http://somewhere/else#)
# rdfs (http://www.w3.org/2000/01/rdf-schema#)
# xsd (http://www.w3.org/2001/XMLSchema#)
# rdf (http://www.w3.org/1999/02/22-rdf-syntax-ns#)
#
# (as expected)

print(g.serialize().decode())

# prints:
#
# <?xml version="1.0" encoding="UTF-8"?>
# <rdf:RDF
#    xmlns:ns1="http://somewhere/else#"
#    xmlns:ns2="http://nowhere/else#"
#    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
# >
#   <rdf:Description rdf:about="http://somewhere/else#y">
#     <ns2:Q rdf:resource="http://somewhere/else#z"/>
#   </rdf:Description>
#   <rdf:Description rdf:about="http://somewhere/else#root">
#     <ns1:P rdf:resource="http://somewhere/else#y"/>
#     <ns1:P rdf:resource="http://somewhere/else#x"/>
#   </rdf:Description>
# </rdf:RDF>
#
# (as expected)

elseNS = Namespace('http://somewhere/else#') # same namespace as ns1 above

g.namespace_manager.bind('there', elseNS, replace=True) # attempt to rebind to other prefix

for ns in g.namespaces():
    print('%s (%s)' % (ns))    

# prints:
#
# xsd (http://www.w3.org/2001/XMLSchema#)
# there (http://somewhere/else#)
# rdfs (http://www.w3.org/2000/01/rdf-schema#)
# rdf (http://www.w3.org/1999/02/22-rdf-syntax-ns#)
# xml (http://www.w3.org/XML/1998/namespace)
# ns2 (http://nowhere/else#)
# ns1 (http://somewhere/else#)
#
# ("there" and "ns1" are bound to the same namespace)

print(g.serialize().decode())

# prints:
#
# <?xml version="1.0" encoding="UTF-8"?>
# <rdf:RDF
#    xmlns:ns1="http://somewhere/else#"
#    xmlns:ns2="http://nowhere/else#"
#    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
# >
#   <rdf:Description rdf:about="http://somewhere/else#root">
#     <ns1:P rdf:resource="http://somewhere/else#x"/>
#     <ns1:P rdf:resource="http://somewhere/else#y"/>
#   </rdf:Description>
#   <rdf:Description rdf:about="http://somewhere/else#y">
#     <ns2:Q rdf:resource="http://somewhere/else#z"/>
#   </rdf:Description>
# </rdf:RDF>
#
# (in the serialization "ns1" is used, not "there" as was intended)
@gromgull
Copy link
Member

The confusion here is the two arguments replace and override

Say they release FOAF 2.0 (Now based on google+? :) ) and you want to change foaf to point to http://xmlns.com/foaf/2.0/. Up to now you had foaf=>http://xmlns.com/foaf/0.1 and foaf2=>http://xmlns.com/foaf/2.0

Now you want to "upgrade" to FOAF 2.0 :

g.namespace_manager.bind('foaf', Namespace('http://xmlns.com/foaf/2.0'), .... )

Adding:

  • override will do what you want, and replace the current binding for foaf to be the new URI.
  • replace will replace any other bindings pointing to the same namespace, so the old foaf2 binding will be removed.

In the FOAF2 example, you probably want both.

@Jeroen537
Copy link
Author

Thanks very much for taking the trouble to respond. I appreciate it.

However, while your solution works in the sense that it does remove the old binding to foaf, it is not a complete answer to my question. What I want to achieve in my code is to remove the old prefix altogether. In that I have not succeeded, with any combinations of replace and override. I also tried to rebind to Namespace(None) and Namespace(''), but to no avail. What I am looking for is an "unbind" method I suppose. Or is there some solution I have not thought of? Thanks again.

Small code example follows. The attempt to remove foaf2 is at the bottom, where I bind foaf3, which works but leaves foaf2 also in place:

from rdflib import Graph, Namespace

g = Graph()

g.namespace_manager.bind('foaf', Namespace('http://xmlns.com/foaf/0.1'))
g.namespace_manager.bind('foaf2', Namespace('http://xmlns.com/foaf/2.0'))

print('--- namespaces after initial bind ---')
for ns in g.namespaces():
    print('%s:%s' % (ns))
print

#--- namespaces after initial bind ---
#xml:http://www.w3.org/XML/1998/namespace
#foaf:http://xmlns.com/foaf/0.1
#rdfs:http://www.w3.org/2000/01/rdf-schema#
#rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
#xsd:http://www.w3.org/2001/XMLSchema#
#foaf2:http://xmlns.com/foaf/2.0

g.namespace_manager.bind('foaf', Namespace('http://xmlns.com/foaf/2.0'), replace=True)

print('--- namespaces after rebind ===')
for ns in g.namespaces():
    print('%s:%s' % (ns))
print

#--- namespaces after rebind ===
#xml:http://www.w3.org/XML/1998/namespace
#foaf:http://xmlns.com/foaf/2.0
#rdfs:http://www.w3.org/2000/01/rdf-schema#
#rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
#xsd:http://www.w3.org/2001/XMLSchema#
#foaf2:http://xmlns.com/foaf/2.0

g.namespace_manager.bind('foaf3', Namespace('http://xmlns.com/foaf/2.0'), override=True, replace=True)

print('--- namespaces after second rebind ===')
for ns in g.namespaces():
    print('%s:%s' % (ns))

#--- namespaces after second rebind ===
#xml:http://www.w3.org/XML/1998/namespace
#foaf:http://xmlns.com/foaf/2.0
#rdfs:http://www.w3.org/2000/01/rdf-schema#
#rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
#xsd:http://www.w3.org/2001/XMLSchema#
#foaf3:http://xmlns.com/foaf/2.0
#foaf2:http://xmlns.com/foaf/2.0

@gromgull
Copy link
Member

Hmm you are right - this IS a bug.

The problem is (maybe) in the individual implementation, for instance, here:

https://github.com/RDFLib/rdflib/blob/master/rdflib/plugins/memory.py#L150

that when replacing, the uri=>prefix is updated correctly (i.e. the http://xmlns.com/foaf/2.0 now points to foaf3) but the prefix=>uri map of course has both. This should be cleaned up if the prefix was already used.

Also, an unbind method would be handy. Sometimes you want to remove a prefix without providing a new one.

@joernhees joernhees reopened this Nov 22, 2015
@joernhees joernhees added bug Something isn't working enhancement New feature or request labels Nov 22, 2015
@joernhees joernhees modified the milestones: rdflib 4.2.2, rdflib 4.3.0 Nov 22, 2015
@joernhees joernhees modified the milestones: rdflib 4.3.0, rdflib 5.0.1 Jan 28, 2016
@white-gecko white-gecko modified the milestones: rdflib 5.0.1, rdflib 5.1.0 Mar 16, 2020
@white-gecko white-gecko modified the milestones: rdflib 5.1.0, rdflib 6.0.0 May 1, 2020
@abhishekvickyvyas
Copy link

abhishekvickyvyas commented May 28, 2020

In PR #1094 , We added an unbind function which can be called in same way in which we call bind function. We pass the prefix that need to be unbind as parameter. The example can be given as:-

from rdflib import Graph, Namespace
g = Graph()
g.namespace_manager.bind('abc', Namespace('http://abc.com/pqr/0.1'))
print('--- namespaces before unbinding ----')
for ns in g.namespaces():
print('%s:%s' % (ns))
print
g.namespace_manager.unbind('abc')
print("\n\n")
print('--- namespaces after unbinding ----')
for ns in g.namespaces():
print('%s:%s' % (ns))
print

@ghost
Copy link

ghost commented Jun 4, 2022

Recently fixed in #1843

def test_namespace_bind():
    from rdflib import Graph, Namespace

    g = Graph()

    g.namespace_manager.bind("foaf", Namespace("http://xmlns.com/foaf/0.1"))
    g.namespace_manager.bind("foaf2", Namespace("http://xmlns.com/foaf/2.0"))

    logger.debug("--- namespaces after initial bind ---")
    for ns in g.namespaces():
        logger.debug("%s:%s" % (ns))

    # ORIG
    # --- namespaces after initial bind ---
    # xml:http://www.w3.org/XML/1998/namespace
    # foaf:http://xmlns.com/foaf/0.1
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#
    # foaf2:http://xmlns.com/foaf/2.0

    # FIXED
    # --- namespaces after initial bind ---
    # owl:http://www.w3.org/2002/07/owl#
    # xml:http://www.w3.org/XML/1998/namespace
    # foaf:http://xmlns.com/foaf/0.1
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#
    # foaf2:http://xmlns.com/foaf/2.0

    g.namespace_manager.bind(
        "foaf", Namespace("http://xmlns.com/foaf/2.0"), replace=True
    )

    logger.debug("--- namespaces after rebind ===")
    for ns in g.namespaces():
        logger.debug("%s:%s" % (ns))

    # ORIG
    # --- namespaces after rebind ===
    # xml:http://www.w3.org/XML/1998/namespace
    # foaf:http://xmlns.com/foaf/2.0
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#
    # foaf2:http://xmlns.com/foaf/2.0

    # FIXED
    # --- namespaces after rebind ===
    # owl:http://www.w3.org/2002/07/owl#
    # xml:http://www.w3.org/XML/1998/namespace
    # foaf:http://xmlns.com/foaf/2.0
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#


    g.namespace_manager.bind(
        "foaf3", Namespace("http://xmlns.com/foaf/2.0"), override=True, replace=True
    )

    logger.debug("--- namespaces after second rebind ===")
    for ns in g.namespaces():
        logger.debug("%s:%s" % (ns))

    # ORIG
    # --- namespaces after second rebind ===
    # xml:http://www.w3.org/XML/1998/namespace
    # foaf:http://xmlns.com/foaf/2.0
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#
    # foaf3:http://xmlns.com/foaf/2.0
    # foaf2:http://xmlns.com/foaf/2.0

    # FIXED
    # --- namespaces after second rebind ===
    # owl:http://www.w3.org/2002/07/owl#
    # xml:http://www.w3.org/XML/1998/namespace
    # rdfs:http://www.w3.org/2000/01/rdf-schema#
    # rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#
    # xsd:http://www.w3.org/2001/XMLSchema#
    # foaf3:http://xmlns.com/foaf/2.0

@ghost ghost closed this as completed Jun 4, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request fix-in-progress
Projects
None yet
Development

No branches or pull requests

5 participants