/** --- XML ---
Classes to represent XML files and their content.
*/
import semmle.code.Location
/** An XMLParent is either an XMLElement or an XMLFile.
* Both classes can contain other elements and are therefore parents. */
class XMLParent extends @xmlparent {
/** get this parent's name; should be overridden in subclasses */
string getName() { result = "parent" }
/** get the file this XML parent comes from */
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
/** get an element that is a child of this parent */
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
/** get a comment that is a child of this parent */
XMLComment getAComment() { xmlComments(result,_,this,_) }
/** get a characters sequence that is a child of this parent */
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
/** gets the depth in the tree. Overridden in XMLElement. */
int getDepth() { result = 0 }
/** computes the number of children*/
int getNumberOfChildren() {
result = count(XMLElement e | xmlElements(e,_,this,_,_))
}
/** gets the number of places in the body of an XML parent where text occurs */
int getNumberOfCharacterSets() {
result = count(int pos | xmlChars(_,_,this,pos,_,_))
}
/** appends the character sets from left to right separated by a space */
string charsSetUpTo(int n) {
(n = 0 and xmlChars(_,result,this,0,_,_)) or
(n > 0 and exists(string chars| xmlChars(_,chars,this,n,_,_) and
result = this.charsSetUpTo(n-1) + " " + chars))
}
/** produces the string that puts all chars next to each other */
string allCharactersString() {
exists(int n | n = this.getNumberOfCharacterSets() and
((n=0 and result = "") or
(n>0 and result = this.charsSetUpTo(n-1))))
}
/** printable representation */
string toString() { result = this.getName() }
/** set icon to represent this parent */
string getIconPath() { result = "icons/tag.png" }
}
/** A parsed XML file */
class XMLFile extends @xmlfile, XMLParent, File {
string toString() { result = XMLParent.super.toString() }
/** get this file's name */
string getName() { files(this,result,_,_,_) }
/** get this file's path */
string getPath() { files(this,_,result,_,_) }
/** get this file's folder */
string getFolder() {
result = this.getPath().substring(1,
this.getPath().length()-this.getName().length())
}
/** get this file's enconding */
string getEncoding() { xmlEncoding(this,result) }
/** get the file this entity belongs to */
XMLFile getFile() { result = this }
/** gives a top most element in an XML file*/
XMLElement getARootElement() { result = this.getAChild() }
/** gives a DTD*/
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
/** set icon to represent this file */
string getIconPath() { result = "icons/file.png" }
}
/** A Document Type Declarations of an XML file */
class XMLDTD extends @xmldtd {
/** get this DTD's root element name */
string getRoot() { xmlDTDs(this,result,_,_,_) }
/** get this DTD's public ID */
string getPublicId() { xmlDTDs(this,_,result,_,_) }
/** get this DTD's system ID */
string getSystemId() { xmlDTDs(this,_,_,result,_) }
/** is this DTD public? */
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
/** get this DTD's parent */
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
/** printable representation */
string toString() {
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
this.getPublicId() + "' '" +
this.getSystemId() + "'") or
(not this.isPublic() and result = this.getRoot() +
" SYSTEM '" +
this.getSystemId() + "'")
}
}
/** An XML tag in an XML file */
class XMLElement extends @xmlelement, XMLParent {
/** get this element's name */
string getName() { xmlElements(this,result,_,_,_) }
/** the qualified name is of the following form:
* <namespace>:<name> or <name> if no namespace for this element is present */
string getQualifiedName() {
exists(XMLNamespace n | this.getNamespace()=n and not n.isDefault() and
result = n.getPrefix() + ":" + this.getName()) or
(not exists(XMLNamespace n | this.getNamespace()=n and not n.isDefault())
and result = this.getName())
}
/** get the file this element appears in */
XMLFile getFile() { xmlElements(this,_,_,_,result) }
/** get this element's parent */
XMLParent getParent() { xmlElements(this,_,result,_,_) }
/** does this element have a namespace? */
predicate hasNamespace() { xmlHasNs(this,_,_) }
/** get this element's namespace (if any) */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
/** get the index of this element */
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
/** gets the depth of this element */
int getDepth() { result = this.getParent().getDepth() + 1 }
/** gives an attribute of this element */
XMLAttribute getAnAttribute() { result.getElement() = this }
/** gives an attribute with a specific name */
XMLAttribute getAttribute(string name) {
result.getElement() = this and result.getName() = name
}
/** does this element have an attribute name? */
predicate hasAttribute(string name) {
exists(XMLAttribute a| a = this.getAttribute(name))
}
/** gives the value of a specific attribute */
string getAttributeValue(string name) {
result = this.getAttribute(name).getValue()
}
/** source location for this element */
Location getLocation() { hasLocation(this,result) }
/** URL for this element */
string getURL() {
if exists(this.getLocation()) then
result = this.getLocation().getURL()
else
result = ""
}
}
/** An attribute that occurs inside an XML element */
class XMLAttribute extends @xmlattribute {
/** get this attribute's name */
string getName() { xmlAttrs(this,_,result,_,_,_) }
/** same as for XML element, the qualified name is of the following form:*/
/** <namespace>:<name> or <name> if no namespace for this attribute is present*/
string getQualifiedName() {
exists(XMLNamespace n | this.getNamespace()=n and not n.isDefault() and
result = n.getPrefix() + ":" + this.getName()) or
(not exists(XMLNamespace n | this.getNamespace()=n and not n.isDefault())
and result = this.getName())
}
/** get the element this attribute belongs to */
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
/** does this attribute have a namespace? */
predicate hasNamespace() { xmlHasNs(this,_,_) }
/** get this attribute's namespace (if any) */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
/** get this attribute's value */
string getValue() { xmlAttrs(this,_,_,result,_,_) }
/** printable representation */
string toString() { result = this.getName() + "=" + this.getValue() }
/** set icon to represent this attribute */
string getIconPath() { result = "icons/publicfield.png" }
}
/** A namespace used in an XML file */
class XMLNamespace extends @xmlnamespace {
/** get the namespace prefix */
string getPrefix() { xmlNs(this,result,_,_) }
/** get the namespace URI */
string getURI() { xmlNs(this,_,result,_) }
/** if this namespace has no prefix, then it is default */
predicate isDefault() { this.getPrefix() = "" }
/** printable representation */
string toString() {
(this.isDefault() and result = this.getURI()) or
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
}
/** set icon to represent this namespace */
string getIconPath() { result = "icons/publicfield.png" }
}
/** A comment of the form <!-- ... --> */
class XMLComment extends @xmlcomment {
/** get comment content */
string getText() { xmlComments(this,result,_,_) }
/** get parent of this comment */
XMLParent getParent() { xmlComments(this,_,result,_) }
/** printable representation */
string toString() { result = this.getText() }
/** set icon to represent this comment */
string getIconPath() { result = "icons/publicfield.png" }
}
class XMLCharacters extends @xmlcharacters {
/** get content of this character sequence */
string getCharacters() { xmlChars(this,result,_,_,_,_) }
/** get the parent of this character sequence */
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
/** is this character sequence CDATA? */
predicate isCDATA() { xmlChars(this,_,_,_,true,_) }
/** printable representation */
string toString() { result = this.getCharacters() }
/** set icon to represent this character sequence */
string getIconPath() { result = "icons/publicfield.png" }
}
|