Example #1
0
static VALUE rxml_node_modify_dom(VALUE self, VALUE target,
                                  xmlNodePtr (*xmlFunc)(xmlNodePtr, xmlNodePtr))
{
  xmlNodePtr xnode, xtarget, xresult;

  if (rb_obj_is_kind_of(target, cXMLNode) == Qfalse)
    rb_raise(rb_eTypeError, "Must pass an XML::Node object");

  xnode = rxml_get_xnode(self);
  xtarget = rxml_get_xnode(target);

  if (xtarget->doc != NULL && xtarget->doc != xnode->doc)
    rb_raise(eXMLError, "Nodes belong to different documents.  You must first import the node by calling XML::Document.import");

  xmlUnlinkNode(xtarget);

  /* This target node could be freed here. */  
  xresult = xmlFunc(xnode, xtarget);

  if (!xresult)
    rxml_raise(&xmlLastError);

  /* Was the target freed? If yes, then wrap the new node */
  if (xresult != xtarget)
  {
    RDATA(target)->data = xresult;
    xresult->_private = (void*) target;
  }

  return target;
}
Example #2
0
/*
 * call-seq:
 *    node.doc -> document
 *
 * Obtain the XML::Document this node belongs to.
 */
static VALUE rxml_node_doc(VALUE self)
{
  xmlDocPtr xdoc = NULL;
  xmlNodePtr xnode = rxml_get_xnode(self);

  switch (xnode->type)
  {
  case XML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
  case XML_DOCB_DOCUMENT_NODE:
#endif
  case XML_HTML_DOCUMENT_NODE:
  case XML_NAMESPACE_DECL:
    break;
  case XML_ATTRIBUTE_NODE:
    xdoc = (xmlDocPtr)((xmlAttrPtr) xnode->doc);
    break;
  default:
    xdoc = xnode->doc;
  }

  if (xdoc == NULL)
    return (Qnil);
  else if (xdoc->_private)
    return (VALUE) xdoc->_private;
  else
    return (Qnil);
}
Example #3
0
/*
 * call-seq:
 *    text_node.output_escaping = true|false
 *    element_node.output_escaping = true|false
 *    attribute_node.output_escaping = true|false
 *
 * Controls whether this text node or the immediate text node children of an
 * element or attribute node escapes their output.  Any other type of node
 * will simply ignore this operation.
 *
 * Text nodes which are added to an element or attribute node will be affected
 * by any previous setting of this property.
 */
static VALUE rxml_node_output_escaping_set(VALUE self, VALUE bool)
{
  xmlNodePtr xnode;
  xnode = rxml_get_xnode(self);

  switch (xnode->type) {
  case XML_TEXT_NODE:
    xnode->name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
    break;
  case XML_ELEMENT_NODE:
  case XML_ATTRIBUTE_NODE:
    {
      const xmlChar *name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
      xmlNodePtr tmp;
      for (tmp = xnode->children; tmp; tmp = tmp->next)
        if (tmp->type == XML_TEXT_NODE)
          tmp->name = name;
    }
    break;
  default:
    return Qnil;
  }

  return (bool!=Qfalse && bool!=Qnil) ? Qtrue : Qfalse;
}
Example #4
0
/*
 * call-seq:
 *    node.space_preserve -> (true|false)
 *
 * Determine whether this node preserves whitespace.
 */
static VALUE rxml_node_space_preserve_get(VALUE self)
{
  xmlNodePtr xnode;

  xnode = rxml_get_xnode(self);
  return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
}
Example #5
0
/*
 * call-seq:
 *    text_node.output_escaping?      -> (true|false)
 *    element_node.output_escaping?   -> (true|false|nil)
 *    attribute_node.output_escaping? -> (true|false|nil)
 *    other_node.output_escaping?     -> (nil)
 *
 * Determine whether this node escapes it's output or not.
 *
 * Text nodes return only +true+ or +false+.  Element and attribute nodes
 * examine their immediate text node children to determine the value.
 * Any other type of node always returns +nil+.
 *
 * If an element or attribute node has at least one immediate child text node 
 * and all the immediate text node children have the same +output_escaping?+
 * value, that value is returned.  Otherwise, +nil+ is returned.
 */
static VALUE rxml_node_output_escaping_q(VALUE self)
{
  xmlNodePtr xnode;
  xnode = rxml_get_xnode(self);

  switch (xnode->type) {
  case XML_TEXT_NODE:
    return xnode->name==xmlStringTextNoenc ? Qfalse : Qtrue;
  case XML_ELEMENT_NODE:
  case XML_ATTRIBUTE_NODE:
    {
      xmlNodePtr tmp = xnode->children;
      const xmlChar *match = NULL;

      /* Find the first text node and use it as the reference. */
      while (tmp && tmp->type != XML_TEXT_NODE)
        tmp = tmp->next;
      if (! tmp)
        return Qnil;
      match = tmp->name;

      /* Walk the remaining text nodes until we run out or one doesn't match. */
      while (tmp && (tmp->type != XML_TEXT_NODE || match == tmp->name))
        tmp = tmp->next;

      /* We're left with either the mismatched node or the aggregate result. */
      return tmp ? Qnil : (match==xmlStringTextNoenc ? Qfalse : Qtrue);
    }
    break;
  default:
    return Qnil;
  }
}
Example #6
0
static VALUE rxml_node_remove_ex(VALUE self)
{
  xmlNodePtr xnode, xresult;
  xnode = rxml_get_xnode(self);

  /* First unlink the node from its parent. */
  xmlUnlinkNode(xnode);

  /* Now copy the node we want to remove and make the
     current Ruby object point to it.  We do this because
     a node has a number of dependencies on its parent
     document - its name (if using a dictionary), entities,
     namespaces, etc.  For a node to live on its own, it
     needs to get its own copies of this information.*/
  xresult = xmlDocCopyNode(xnode, NULL, 1);
  
  /* Now free the original node. */
  xmlFreeNode(xnode);

  /* Now wrap the new node */
  RDATA(self)->data = xresult;
  xresult->_private = (void*) self;

  /* Now return the removed node so the user can
     do something with it.*/
  return self;
}
Example #7
0
/*
 * call-seq:
 *    node.attributes -> attributes
 *
 * Returns the XML::Attributes for this node.
 */
static VALUE rxml_node_attributes_get(VALUE self)
{
  xmlNodePtr xnode;

  xnode = rxml_get_xnode(self);
  return rxml_attributes_new(xnode);
}
Example #8
0
/*
 * call-seq:
 *    node.prev -> XML::Node
 *
 * Obtain the previous sibling, if any.
 */
static VALUE rxml_node_prev_get(VALUE self)
{
  xmlNodePtr xnode;
  xmlNodePtr node;
  xnode = rxml_get_xnode(self);

  switch (xnode->type)
  {
  case XML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
    case XML_DOCB_DOCUMENT_NODE:
#endif
  case XML_HTML_DOCUMENT_NODE:
  case XML_NAMESPACE_DECL:
    node = NULL;
    break;
  case XML_ATTRIBUTE_NODE:
  {
    xmlAttrPtr attr = (xmlAttrPtr) xnode;
    node = (xmlNodePtr) attr->prev;
  }
    break;
  default:
    node = xnode->prev;
    break;
  }

  if (node == NULL)
    return (Qnil);
  else
    return (rxml_node_wrap(node));
}
Example #9
0
/*
 * call-seq:
 *   curr_node << "Some text" 
 *   curr_node << node
 *
 * Add  the specified text or XML::Node as a new child node to the 
 * current node.
 *
 * If the specified argument is a string, it should be a raw string 
 * that contains unescaped XML special characters.  Entity references 
 * are not supported.
 * 
 * The method will return the current node.
 */
static VALUE rxml_node_content_add(VALUE self, VALUE obj)
{
  xmlNodePtr xnode;
  VALUE str;

  xnode = rxml_get_xnode(self);

  /* XXX This should only be legal for a CDATA type node, I think,
   * resulting in a merge of content, as if a string were passed
   * danj 070827
   */
  if (rb_obj_is_kind_of(obj, cXMLNode))
  { 
    rxml_node_modify_dom(self, obj, xmlAddChild);
  }
  else
  {
    str = rb_obj_as_string(obj);
    if (NIL_P(str) || TYPE(str) != T_STRING)
      rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");

    xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
  }
  return self;
}
Example #10
0
/*
 * call-seq:
 *    node.space_preserve = true|false
 *
 * Control whether this node preserves whitespace.
 */
static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
{
  xmlNodePtr xnode;
  xnode = rxml_get_xnode(self);

  if (TYPE(bool) == T_FALSE)
    xmlNodeSetSpacePreserve(xnode, 0);
  else
Example #11
0
/*
 * call-seq:
 *    node.empty? -> (true|false)
 *
 * Determine whether this node is an empty or whitespace only text-node.
 */
static VALUE rxml_node_empty_q(VALUE self)
{
  xmlNodePtr xnode;
  xnode = rxml_get_xnode(self);
  if (xnode == NULL)
    return (Qnil);

  return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse);
}
Example #12
0
/*
 * call-seq:
 *    node.content = "string"
 *
 * Set this node's content to the specified string.
 */
static VALUE rxml_node_content_set(VALUE self, VALUE content)
{
  xmlNodePtr xnode;

  Check_Type(content, T_STRING);
  xnode = rxml_get_xnode(self);
  // XXX docs indicate need for escaping entites, need to be done? danj
  xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
  return (Qtrue);
}
Example #13
0
/*
 * call-seq:
 *    node.lang = "string"
 *
 * Set the language for this node. This affects the value
 * of the xml:lang attribute.
 */
static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
{
  xmlNodePtr xnode;

  Check_Type(lang, T_STRING);
  xnode = rxml_get_xnode(self);
  xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));

  return (Qtrue);
}
Example #14
0
/*
 * call-seq:
 *    node.first -> XML::Node
 *
 * Returns this node's first child node if any.
 */
static VALUE rxml_node_first_get(VALUE self)
{
  xmlNodePtr xnode;

  xnode = rxml_get_xnode(self);

  if (xnode->children)
    return (rxml_node_wrap(xnode->children));
  else
    return (Qnil);
}
Example #15
0
/*
 * call-seq:
 *    node.content = "string"
 *
 * Set this node's content to the specified string.
 */
static VALUE rxml_node_content_set(VALUE self, VALUE content)
{
  xmlNodePtr xnode;
  xmlChar* encoded_content;

  Check_Type(content, T_STRING);
  xnode = rxml_get_xnode(self);
  encoded_content = xmlEncodeSpecialChars(xnode->doc, (xmlChar*) StringValuePtr(content));
  xmlNodeSetContent(xnode, encoded_content);
  return (Qtrue);
}
Example #16
0
/*
 * call-seq:
 *    node.parent -> XML::Node
 *
 * Obtain this node's parent node, if any.
 */
static VALUE rxml_node_parent_get(VALUE self)
{
  xmlNodePtr xnode;

  xnode = rxml_get_xnode(self);

  if (xnode->parent)
    return (rxml_node_wrap(xnode->parent));
  else
    return (Qnil);
}
Example #17
0
static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
{
  VALUE result = Qnil;
  VALUE options = Qnil;
  xmlNodePtr xnode;
  xmlCharEncodingHandlerPtr encodingHandler;
  xmlOutputBufferPtr output;

  int level = 0;
  int indent = 1;
  const char *xencoding = "UTF-8";

  rb_scan_args(argc, argv, "01", &options);

  if (!NIL_P(options))
  {
    VALUE rencoding, rindent, rlevel;
    Check_Type(options, T_HASH);
    rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
    rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
    rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level")));

    if (rindent == Qfalse)
      indent = 0;

    if (rlevel != Qnil)
      level = NUM2INT(rlevel);

    if (rencoding != Qnil)
    {
      xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
      if (!xencoding)
        rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
    }
  }

  encodingHandler = xmlFindCharEncodingHandler(xencoding);
  output = xmlAllocOutputBuffer(encodingHandler);

  xnode = rxml_get_xnode(self);

  xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, xencoding);
  xmlOutputBufferFlush(output);

  if (output->conv)
    result = rxml_new_cstr((const char*) output->conv->content, xencoding);
  else
    result = rxml_new_cstr((const char*) output->buffer->content, xencoding);

  xmlOutputBufferClose(output);
  
  return result;
}
Example #18
0
/*
 * call-seq:
 *    node.debug -> true|false
 *
 * Print libxml debugging information to stdout.
 * Requires that libxml was compiled with debugging enabled.
*/
static VALUE rxml_node_debug(VALUE self)
{
#ifdef LIBXML_DEBUG_ENABLED
  xmlNodePtr xnode;
  xnode = rxml_get_xnode(self);
  xmlDebugDumpNode(NULL, xnode, 2);
  return Qtrue;
#else
  rb_warn("libxml was compiled without debugging support.")
  return Qfalse;
#endif
}
Example #19
0
/*
 * call-seq:
 *    node.base_uri = "uri"
 *
 * Set this node's base URI.
 */
static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri)
{
  xmlNodePtr xnode;

  Check_Type(uri, T_STRING);
  xnode = rxml_get_xnode(self);
  if (xnode->doc == NULL)
    return (Qnil);

  xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri));
  return (Qtrue);
}
Example #20
0
/*
 * call-seq:
 *    node.path -> path
 *
 * Obtain this node's path.
 */
static VALUE rxml_node_path(VALUE self)
{
  xmlNodePtr xnode;
  xmlChar *path;

  xnode = rxml_get_xnode(self);
  path = xmlGetNodePath(xnode);

  if (path == NULL)
    return (Qnil);
  else
    return (rxml_new_cstr((const char*) path, NULL));
}
Example #21
0
/*
 * call-seq:
 *    node.xlink_type -> num
 *
 * Obtain the type identifier for this xlink, if applicable.
 * If this is not an xlink node (see +xlink?+), will return
 * nil.
 */
static VALUE rxml_node_xlink_type(VALUE self)
{
  xmlNodePtr xnode;
  xlinkType xlt;

  xnode = rxml_get_xnode(self);
  xlt = xlinkIsLink(xnode->doc, xnode);

  if (xlt == XLINK_TYPE_NONE)
    return (Qnil);
  else
    return (INT2NUM(xlt));
}
Example #22
0
/*
 * call-seq:
 *    node.xlink? -> (true|false)
 *
 * Determine whether this node is an xlink node.
 */
static VALUE rxml_node_xlink_q(VALUE self)
{
  xmlNodePtr xnode;
  xlinkType xlt;

  xnode = rxml_get_xnode(self);
  xlt = xlinkIsLink(xnode->doc, xnode);

  if (xlt == XLINK_TYPE_NONE)
    return (Qfalse);
  else
    return (Qtrue);
}
Example #23
0
/*
 * call-seq:
 *    node.name = "string"
 *
 * Set this node's name.
 */
static VALUE rxml_node_name_set(VALUE self, VALUE name)
{
  xmlNodePtr xnode;
  const xmlChar *xname;

  Check_Type(name, T_STRING);
  xnode = rxml_get_xnode(self);
  xname = (const xmlChar*)StringValuePtr(name);

	/* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
  xmlNodeSetName(xnode, xname);

  return (Qtrue);
}
Example #24
0
/*
 * call-seq:
 *    node.line_num -> num
 *
 * Obtain the line number (in the XML document) that this
 * node was read from. If +default_line_numbers+ is set
 * false (the default), this method returns zero.
 */
static VALUE rxml_node_line_num(VALUE self)
{
  xmlNodePtr xnode;
  long line_num;
  xnode = rxml_get_xnode(self);

  if (!xmlLineNumbersDefaultValue)
    rb_warn(
        "Line numbers were not retained: use XML::Parser::default_line_numbers=true");

  line_num = xmlGetLineNo(xnode);
  if (line_num == -1)
    return (Qnil);
  else
    return (INT2NUM((long) line_num));
}
Example #25
0
/*
 * call-seq:
 *    node.content -> "string"
 *
 * Obtain this node's content as a string.
 */
static VALUE rxml_node_content_get(VALUE self)
{
  xmlNodePtr xnode;
  xmlChar *content;
  VALUE result = Qnil;

  xnode = rxml_get_xnode(self);
  content = xmlNodeGetContent(xnode);
  if (content)
  {
    result = rxml_new_cstr((const char *) content, NULL);
    xmlFree(content);
  }

  return result;
}
Example #26
0
/*
 * call-seq:
 *    node.lang -> "string"
 *
 * Obtain the language set for this node, if any.
 * This is set in XML via the xml:lang attribute.
 */
static VALUE rxml_node_lang_get(VALUE self)
{
  xmlNodePtr xnode;
  xmlChar *lang;
  VALUE result = Qnil;

  xnode = rxml_get_xnode(self);
  lang = xmlNodeGetLang(xnode);

  if (lang)
  {
    result = rxml_new_cstr((const char*) lang, NULL);
    xmlFree(lang);
  }

  return (result);
}
Example #27
0
/*
 * call-seq:
 *    node.each -> XML::Node
 *
 * Iterates over this node's children, including text
 * nodes, element nodes, etc.  If you wish to iterate
 * only over child elements, use XML::Node#each_element.
 *
 *  doc = XML::Document.new('model/books.xml')
 *  doc.root.each {|node| puts node}
 */
static VALUE rxml_node_each(VALUE self)
{
  xmlNodePtr xnode;
  xmlNodePtr xcurrent;
  xnode = rxml_get_xnode(self);

  xcurrent = xnode->children;

  while (xcurrent)
  {
    /* The user could remove this node, so first stache
       away the next node. */
    xmlNodePtr xnext = xcurrent->next;

    rb_yield(rxml_node_wrap(xcurrent));
    xcurrent = xnext;
  }
  return Qnil;
}
Example #28
0
/*
 * call-seq:
 *    node.base_uri -> "uri"
 *
 * Obtain this node's base URI.
 */
static VALUE rxml_node_base_uri_get(VALUE self)
{
  xmlNodePtr xnode;
  xmlChar* base_uri;
  VALUE result = Qnil;

  xnode = rxml_get_xnode(self);

  if (xnode->doc == NULL)
    return (result);

  base_uri = xmlNodeGetBase(xnode->doc, xnode);
  if (base_uri)
  {
    result = rxml_new_cstr((const char*) base_uri, NULL);
    xmlFree(base_uri);
  }

  return (result);
}
Example #29
0
/*
 * call-seq:
 *    node.name -> "string"
 *
 * Obtain this node's name.
 */
static VALUE rxml_node_name_get(VALUE self)
{
  xmlNodePtr xnode;
  const xmlChar *name;

  xnode = rxml_get_xnode(self);

  switch (xnode->type)
  {
  case XML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
    case XML_DOCB_DOCUMENT_NODE:
#endif
  case XML_HTML_DOCUMENT_NODE:
  {
    xmlDocPtr doc = (xmlDocPtr) xnode;
    name = doc->URL;
    break;
  }
  case XML_ATTRIBUTE_NODE:
  {
    xmlAttrPtr attr = (xmlAttrPtr) xnode;
    name = attr->name;
    break;
  }
  case XML_NAMESPACE_DECL:
  {
    xmlNsPtr ns = (xmlNsPtr) xnode;
    name = ns->prefix;
    break;
  }
  default:
    name = xnode->name;
    break;
  }

  if (xnode->name == NULL)
    return (Qnil);
  else
    return (rxml_new_cstr((const char*) name, NULL));
}
Example #30
0
/*
 * call-seq:
 *    node.xlink_type_name -> "string"
 *
 * Obtain the type name for this xlink, if applicable.
 * If this is not an xlink node (see +xlink?+), will return
 * nil.
 */
static VALUE rxml_node_xlink_type_name(VALUE self)
{
  xmlNodePtr xnode;
  xlinkType xlt;

  xnode = rxml_get_xnode(self);
  xlt = xlinkIsLink(xnode->doc, xnode);

  switch (xlt)
  {
  case XLINK_TYPE_NONE:
    return (Qnil);
  case XLINK_TYPE_SIMPLE:
    return (rxml_new_cstr("simple", NULL));
  case XLINK_TYPE_EXTENDED:
    return (rxml_new_cstr("extended", NULL));
  case XLINK_TYPE_EXTENDED_SET:
    return (rxml_new_cstr("extended_set", NULL));
  default:
    rb_fatal("Unknowng xlink type, %d", xlt);
  }
}