Saturday, August 18, 2018

ColdFusion member functions for XML object management

Prior to ColdFusion 2018, ColdFusion supported the following XML member functions:

Since ColdFusion also supports using array and structure functions to manage XML document objects, I filed CF-4199973 to add the relevant string, struct and array member functions on XML variables.

ColdFusion 2018 added the following XML member functions:

* - Covered by CF-4199973.

** - Pending in CF-4203285.

Observation 1:
.clear() would seemingly be ambiguous, since ArrayClear() and StructClear() can both be used on an XML object. However, ArrayClear(xml) actually *deletes* nodes and its functionality is already covered by StructDelete() and ArrayDeleteAt(). ArrayClear(xmlFoo.xmlBar) deletes all nodes named 'xmlBar' under xmlFoo (equivalent of StructDelete(xmlFoo, "xmlBar")). ArrayClear(xmlFoo.xmlBar[2]) deletes the second node named 'xmlBar' under xmlFoo (equivalent of ArrayDeleteAt(xmlFoo.xmlBar, 2)). So, xmlObject.clear()/XMLClear(xmlObject) should be added to cover StructClear(xmlObject)'s functionality. StructClear(xmlFoo.xmlBar) and StructClear(xmlFoo.xmlBar[1]) clear (convert to empty node) the first node named 'xmlBar' under xmlFoo. ArrayClear() Repro: https://trycf.com/gist/49487fe7e971236bafe0a6685374ca86/acf2018?theme=monokai. StructClear() Repro: https://trycf.com/gist/e04db3702a5bdbbe06de6896639452c5/acf2018?theme=monokai.
Observation 2:
No equivalent for StructDelete() was added. StructDelete(xmlFoo, "xmlBar") deletes all nodes named 'xmlBar' under xmlFoo. So, xmlObject.delete(childName)/XMLDelete(xmlObject, childName) should be added to cover StructDelete(xmlObject, childName)'s functionality. Repro: https://trycf.com/gist/493f0ae6ba00a7d2b528394fa36a1898/acf2018?theme=monokai.
Observation 3:
No equivalent for ArrayDeleteAt() was added. ArrayDeleteAt(xmlFoo.xmlBar, 2) deletes the second node named 'xmlBar' under xmlFoo. So, xmlObject.deleteAt(position)/XMLDeleteAt(xmlObject, position) should be added to cover ArrayDeleteAt(xmlObject, position)'s functionality. Repro: https://trycf.com/gist/1aa6b58603f20739907bfa21ff540ff5/acf2018?theme=monokai.
Observation 4:
Equivalent for Duplicate() exists in CF2016 for all data types. So, XMLDuplicate(xmlObject) does not need added. Repro: https://trycf.com/gist/87b44d40d3400dfa97b4d19911b58a07/acf2016?theme=monokai.
Observation 5:
.isEmpty() was not added because .hasChild() makes more sense in the context of XML and because it would've been ambiguous, since ArrayIsEmpty() and StructIsEmpty() can both be used on an XML object. ArrayIsEmpty(xmlFoo.xmlBar) returns YES if xmlFoo contains any nodes named 'xmlBar'. Whereas, StructIsEmpty(xmlFoo.xmlBar) returns YES if xmlBar contains any nodes. Repro: https://trycf.com/gist/9a73f736757625ecd6f6f9695c8fea65/acf2018?theme=monokai.
Observation 6:
.hasChild() currently doesn't work (always returns YES) and, if it did, only covers StructIsEmpty()'s functionality but not ArrayIsEmpty's. So, xmlObject.hasChild([childName])/XMLHasChild(xmlObject[, childName]) needs an optional 'childName' parameter, in order to also cover ArrayIsEmpty(xmlObject.childName)'s functionality. Repro: https://trycf.com/gist/0db692627ccefdfbe436e756988c10c1/acf2018?theme=monokai.
Observation 7:
No equivalent for Len() was added. Len(xmlObject) implicitly casts xmlObject to string and returns the string's length. However, IMO, an equivalent XML member function for Len(xmlObject) does not need added since: 1) it's undocumented functionality, 2) xmlObject.toString().len() covers its functionality and, more importantly IMO, 3) xmlObject.len() is needed to, and currently does, cover ArrayLen(xmlObject)'s functionality. Repro: https://trycf.com/gist/e0b20bf374a84f279f38974268813ec4/acf2018?theme=monokai.
Observation 8:
ArrayLen(), like a few of the others, is not completely documented. ArrayLen(xmlFoo.xmlBar) counts the nodes named 'xmlBar' under xmlFoo. See Repro for Observation 7.
Observation 9:
StructGet() does not support array notation when referencing an XML object. So, StructGet() needs fixed to support array notation when referencing an XML object. Repro: https://trycf.com/gist/baa6a4aeeec368e6567efe5cf827ee4c/acf2018?theme=monokai
Observation 10:
Since ToString() is not XML-specific, the XMLToString(xmlObject) BIF does not need added.
Observation 11:
Currently, xmlObject.update() returns a struct that doesn't contain, for example, the updated xmlText. So, xmlObject.update() needs fixed to return the updated XML. Repro: https://trycf.com/gist/4031ebc027c788574948183387b56b68/acf2018?theme=monokai
Observation 12:
The "Supported XML member functions" list isn't, but should be, alphabetical. And it should consistently use 'someVar' like the other member function list tables. And the list's purpose isn't for showing syntax, so "xmlObject.update(String key, Object value)" should just be "someVar.update()". And XmlLen/someVar.len() is missing and needs added. And .toString(), added to XML in CF2018, isn't listed but should be. And .duplicate() also exists on XML, but isn't listed and should be.

Once all the issues are fixed, the "Supported XML member functions" doc list should look like (w/ non-XML-specific at bottom):


# XmlAppend someVar.append()
XmlChildPos someVar.childPos()
# XmlClear someVar.clear()
# XmlCount someVar.count()
# XmlDelete someVar.delete()
# XmlDeleteAt someVar.deleteAt()
XmlElemNew someVar.elemNew()
XmlGetNodeType someVar.getNodeType()
# XmlHasChild someVar.hasChild()
# XmlLen someVar.len()
# XmlKeyArray someVar.keyArray()
# XmlKeyList someVar.keyList()
XmlSearch someVar.search()
XmlTransform someVar.transform()
# XmlUpdate someVar.update()
Duplicate someVar.duplicate()
# ToString someVar.toString()

# New in Adobe ColdFusion (2018 release)


Verified in build 2018.0.0.310739.
Filed observations #1, #2, #3, #6 and #11 as CF-4203285.
Filed observation #9 as CF-4203287.
Filed observation #12 as CF-4203286.

ColdFusion member functions for XML object management

Prior to ColdFusion 2018, ColdFusion supported the following XML member functions : .elemNew() (equivalent of XmlElemNew ) .childPos(...