loading...

Kinx Library - XML

krayg profile image Kray-G ・5 min read

Hello, everybody!

The script language Kinx is published with the concept of Looks like JavaScript, Feels like Ruby, Stable like AC/DC(?).

This time it's an XML library.

XML is also often used, so it will be one of what a lot of people want to use easily with a scripting language.

XML

Parsing DOM

Build a DOM tree using Xml.parseFile() or Xml.parseString(). To read the file, do the following.

var doc = Xml.parseFile("xmlfile.xml");

The following is an example of directly parsing a string.

var doc = Xml.parseString(%{
<?xml version="1.0" encoding="UTF-8" ?>
<artists>
  <product country="US" id="1">
    <name>Power Snack</name>
    <price>2400</price>
    <img file="powersnack.jpg"/>
  </product>
  <product country="US" id="2">
    <name>Babystar Icecream</name>
    <price>21000</price>
    <img file="babystar.jpg"/>
  </product>
  <product country="DE" id="3">
    <name>Panic! Panic! Panic!</name>
    <price>2400</price>
    <img file="panic.jpg"/>
  </product>
</artists>
});

The returned document object has the following methods.

Method Content
documentElement() Gets the root document
createElement(tagname) Creates an Element node
createTextNode(text) Creates a Text node
createComment(comment) Creates a Comment node
createCdataSection(content) Creates a CDATA Section node
createProcessingInstruction(target, data) Creates a Processing Instruction node
createEntityReference(name) Creates an Entity Reference node
createElementNS(nsUri, qname) Creates an Element node by specifying the namespace
getElementById(id) Search for a node by specifying id
getElementsByTagName(tagName) Returns the node of tagName as an array
xpath(expr) Evaluates the XPATH of expr and returns the result as an array

Root node

The root node is obtained using the documentElement() method as follows.

var root = doc.documentElement();

XML node

XML nodes, including the root node, have the following properties and methods.

Properties
Properties Content
type Node type
name QName
tagName Tag name
localName Local name
namespaceURI Namespace URI
prefix Prefix

Methods

Method Content
attributes() Returns an attribute list as an array.
setAttribute(qname, value) Set the attribute.
setAttributeNS(nsUri, qname, value) Set the attribute by specifying the namespace.
removeAttribute(qname) Removes an attribute.
removeAttributeNS(nsUri, localName) Removes the attribute by specifying the namespace.
parentNode() Returns the parent node.
children() Returns the child nodes as an array.
firstChild() Returns the first child node.
lastChild() Returns the last child node.
nextSibling() Returns the next node.
previousSibling() Returns the previous node.
appendChild(node) Adds a node to the child node.
removeChild(node) Removes a node from child nodes.
replaceChild(node1, node2) Replaces the child node.
replaceNode(node) Replaces one's own node with another node.
insertBefore(node) Add a node as the previous node.
insertAfter(node) Add a node as the next node.
remove() Removes the node.
textContent() Gets the text.
innerText() Gets the text.
hasChildren() Returns 1 if a child node exists.
hasAttributes() Returns 1 if there are attributes.
getElementById(id) Search for a node by specifying id
getElementsByTagName(tagName) Returns the node of tagName as an array
xpath(expr) Evaluates the XPATH of expr and returns the result as an array

XPath

XPath returns the nodes that match the XPATH expression in the form of a node set (array). The node set also has an xpath() method, and you can use it by chaining XPATH to the narrowed down nodes.

Run the following with the sample XML document above.

var nodes = doc.xpath("//product")
               .xpath("price")
               .map(&(p) => p.innerText());

nodes.each(&(text) => {
    System.println(text);
});

Result.

2400
21000
2400

By the way, using a block syntax and a numbered parameter supported recently, you can also write the following.

var nodes = doc.xpath("//product")
               .xpath("price")
               .map { => _1.innerText() };

nodes.each {
    System.println(_1);
};

Sample source

I introduce the sample source included in the repo. There is Xml.Writer which is not explained, but I think it will be helpful as it is an example that can do DOM parsing like this.

function displayXml(doc, node, indent) {
    System.print("  " * indent);
    if (node.type == Xml.ELEMENT_NODE) {
        System.print("ELEM %s" % node.name);
    } else if (node.type == Xml.TEXT_NODE) {
        System.print("TEXT %s" % node.value.trim());
    }

    var attr = node.attributes();
    for (var i = 0, len = attr.length(); i < len; ++i) {
        System.print("[%s=%s]" % attr[i].name % attr[i].value);
    }
    System.println("");

    var child = node.firstChild();
    while (child) {
        displayXml(doc, child, indent + 1);
        child = child.nextSibling();
    }
}

var doc = Xml.parseString(%{
<?xml version="1.0" encoding="UTF-8" ?>
<artists>
  <product country="US" id="1">
    <name>Power Snack</name>
    <price>2400</price>
    <img file="powersnack.jpg"/>
  </product>
  <product country="US" id="2">
    <name>Babystar Icecream</name>
    <price>21000</price>
    <img file="babystar.jpg"/>
  </product>
  <product country="DE" id="3">
    <name>Panic! Panic! Panic!</name>
    <price>2400</price>
    <img file="panic.jpg"/>
  </product>
</artists>
});
var root = doc.documentElement();
displayXml(doc, root);

var el = root.getElementById("3");
if (el) {
    el.remove();
}

System.println("");
System.println("getElementByTagName:");
var els = root.getElementsByTagName("img");
if (els.isArray) {
    els.each(&(el) => displayXml(doc, el));
}

System.println("");
System.println("XPath:");
var nodes = doc.xpath("//product").xpath("price");
if (nodes.isArray) {
    nodes.each(&(el) => displayXml(doc, el));
}

var xmlWriter = new Xml.Writer(System);
xmlWriter.write(doc);
xmlWriter.write(root);

Execution result.

ELEM artists
  TEXT
  ELEM product[country=US][id=1]
    TEXT
    ELEM name
      TEXT Power Snack
    TEXT
    ELEM price
      TEXT 2400
    TEXT
    ELEM img[file=powersnack.jpg]
    TEXT
  TEXT
  ELEM product[country=US][id=2]
    TEXT
    ELEM name
      TEXT Babystar Icecream
    TEXT
    ELEM price
      TEXT 21000
    TEXT
    ELEM img[file=babystar.jpg]
    TEXT
  TEXT
  ELEM product[country=DE][id=3]
    TEXT
    ELEM name
      TEXT Panic! Panic! Panic!
    TEXT
    ELEM price
      TEXT 2400
    TEXT
    ELEM img[file=panic.jpg]
    TEXT
  TEXT

getElementByTagName:
ELEM img[file=powersnack.jpg]
ELEM img[file=babystar.jpg]

XPath:
ELEM price
  TEXT 2400
ELEM price
  TEXT 21000
<artists>
        <product country="US" id="1">
                <name>Power Snack</name>
                <price>2400</price>
                <img file="powersnack.jpg" />
        </product>
        <product country="US" id="2">
                <name>Babystar Icecream</name>
                <price>21000</price>
                <img file="babystar.jpg" />
        </product>
</artists>
<artists>
        <product country="US" id="1">
                <name>Power Snack</name>
                <price>2400</price>
                <img file="powersnack.jpg" />
        </product>
        <product country="US" id="2">
                <name>Babystar Icecream</name>
                <price>21000</price>
                <img file="babystar.jpg" />
        </product>
</artists>

Conclusion

It would be nice to be able to use XPath.

And if you combine XML and Zip, you can actually read and write Xlsx files (Excel files). The Xlsx file is standardized under the name Office Open XML (with various problems), and it is created by the XML file and a Zip file, so you can read it.

However, in fact, supporting all of Office Open XML requires a lot of codes, so what I can do right away will be just a simple reading and writing. If I have time, I will challenge it.

See you next time.

Posted on by:

krayg profile

Kray-G

@krayg

Although I used to be a C++/Boost lover, I was back to C with the spirit of Zen, or the spirit of "simple is the best". Also returning to rock and roll from metal, I'm really into Rolling Stones.

Discussion

pic
Editor guide