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

Element#replace with CDATA raises error on JRuby #1666

Closed
mrzasa opened this issue Jul 24, 2017 · 5 comments
Closed

Element#replace with CDATA raises error on JRuby #1666

mrzasa opened this issue Jul 24, 2017 · 5 comments

Comments

@mrzasa
Copy link

mrzasa commented Jul 24, 2017

Summary

When I try to replace element with CDATA on JRuby, I got an error RuntimeError: org.jruby.exceptions.RaiseException: (RuntimeError) could not replace child: org.w3c.dom.DOMException: NOT_SUPPORTED_ERR: The implementation does not support the requested type of object or operation.. What is even more strange, element is replaced. It works without problems on MRI. Please, see examples below.

Examples

# replace.rb
require 'rubygems'
require 'nokogiri'
doc = Nokogiri::XML('<parent><child>text</child></parent>')
doc.children.first.children.first.replace(doc.create_cdata("<b>text</b>"))
puts doc

Expected behaviour (MRI)

$ ruby replace.rb 
<?xml version="1.0"?>
<parent><![CDATA[<b>text</b>]]></parent>

Actual behaviour (JRuby)

$ ruby replace.rb 
RuntimeError: org.jruby.exceptions.RaiseException: (RuntimeError) could not replace child: org.w3c.dom.DOMException: NOT_SUPPORTED_ERR: The implementation does not support the requested type of object or operation. 
  replace_node at nokogiri/XmlNode.java:1730
       replace at /home/user/.rvm/gems/jruby-9.1.5.0/gems/nokogiri-1.8.0-java/lib/nokogiri/xml/node.rb:281
        <main> at replace.rb:4

When I run the script line by line in console, it appears that puts doc gives the same result as on MRI:

<?xml version="1.0"?>
<parent><![CDATA[<b>text</b>]]></parent>

element is replaced, but error is raised afterwards.

Env info

Ubuntu 16.10

JRuby Nokogiri:

$ nokogiri -v
# Nokogiri (1.8.0)
    ---
    warnings: []
    nokogiri: 1.8.0
    ruby:
      version: 2.3.1
      platform: java
      description: jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 Java HotSpot(TM) 64-Bit Server VM 25.131-b11 on 1.8.0_131-b11 +jit [linux-x86_64]
      engine: jruby
      jruby: 9.1.5.0
    xerces: Xerces-J 2.11.0
    nekohtml: NekoHTML 1.9.21

MRI Nokogiri:

$ nokogiri -v
# Nokogiri (1.8.0)
    ---
    warnings: []
    nokogiri: 1.8.0
    ruby:
      version: 2.3.3
      platform: x86_64-linux
      description: ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-linux]
      engine: ruby
    libxml:
      binding: extension
      source: packaged
      libxml2_path: "/home/user/.rvm/gems/ruby-2.3.3/gems/nokogiri-1.8.0/ports/x86_64-pc-linux-gnu/libxml2/2.9.4"
      libxslt_path: "/home/user/.rvm/gems/ruby-2.3.3/gems/nokogiri-1.8.0/ports/x86_64-pc-linux-gnu/libxslt/1.1.29"
      libxml2_patches:
      - 0001-Fix-comparison-with-root-node-in-xmlXPathCmpNodes.patch
      - 0002-Fix-XPointer-paths-beginning-with-range-to.patch
      - 0003-Disallow-namespace-nodes-in-XPointer-ranges.patch
      libxslt_patches:
      - 0001-Fix-heap-overread-in-xsltFormatNumberConversion.patch
      - 0002-Check-for-integer-overflow-in-xsltAddTextString.patch
      compiled: 2.9.4
      loaded: 2.9.4
@mrzasa
Copy link
Author

mrzasa commented Jul 26, 2017

I've found a workaround: if CDATA element is wrapped in NodeSet, no exception is raised:

# replace.rb
require 'rubygems'
require 'nokogiri'
doc = Nokogiri::XML('<parent><child>text</child></parent>')
set = Nokogiri::XML::NodeSet.new(doc, [doc.create_cdata("<b>text</b>")])
doc.children.first.children.first.replace(set)
puts doc

@flavorjones
Copy link
Member

Apologies for the embarrassingly long response time.

I've confirmed this behavior, investigating.

@flavorjones
Copy link
Member

OK, the offending code is at https://github.com/sparklemotion/nokogiri/blob/v1.8.2/ext/java/nokogiri/XmlNode.java#L1707-L1710 which I'll reproduce here:

parentNode.replaceChild(otherNode, thisNode);
if (otherNode.getNodeType() != Node.TEXT_NODE) {
    NokogiriHelpers.renameNode(otherNode, thisNode.getNamespaceURI(), otherNode.getNodeName());
}

The first function call, replaceChild(), succeeds (which explains why the document structure is as-expected). It's the second call, renameNode(), which is failing. This makes sense, because renameNode() attempts to make sure the node's namespace matches what we'd expect from a real tag, and not from a CDATA node.

The solution is going to be skipping that call for CDATA as well as text nodes.

@flavorjones
Copy link
Member

Closed by 80205c4

@mrzasa
Copy link
Author

mrzasa commented Mar 21, 2018

Thanks, @flavorjones :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants