Add Get Current XPath
This commit also moves some shared code to a common class. Issue: #85
This commit is contained in:
parent
af2060dc38
commit
6a92fa96f2
10 changed files with 223 additions and 84 deletions
|
|
@ -2,3 +2,4 @@ export * from "./configuration";
|
|||
export * from "./create-document-selector";
|
||||
export * from "./extension-state";
|
||||
export * from "./native-commands";
|
||||
export * from "./xml-traverser";
|
||||
|
|
|
|||
129
src/common/xml-traverser.ts
Normal file
129
src/common/xml-traverser.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import { Position } from "vscode";
|
||||
import { DOMParser } from "xmldom";
|
||||
|
||||
export class XmlTraverser {
|
||||
|
||||
constructor(private _xmlDocument: Document) { }
|
||||
|
||||
get xmlDocument(): Document {
|
||||
return this._xmlDocument;
|
||||
}
|
||||
|
||||
set xmlDocument(value: Document) {
|
||||
this._xmlDocument = value;
|
||||
}
|
||||
|
||||
getChildAttributeArray(node: Element): any[] {
|
||||
if (!node.attributes) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const array = new Array<any>();
|
||||
|
||||
for (let i = 0; i < node.attributes.length; i++) {
|
||||
array.push(node.attributes[i]);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
getChildElementArray(node: Node): any[] {
|
||||
if (!node.childNodes) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const array = new Array<any>();
|
||||
|
||||
for (let i = 0; i < node.childNodes.length; i++) {
|
||||
const child = node.childNodes[i];
|
||||
|
||||
if (this.isElement(child)) {
|
||||
array.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
getElementAtPosition(position: Position): Element {
|
||||
const node = this.getNodeAtPosition(position);
|
||||
|
||||
return this.getNearestElementAncestor(node);
|
||||
}
|
||||
|
||||
getNearestElementAncestor(node: Node): Element {
|
||||
if (!this.isElement) {
|
||||
return this.getNearestElementAncestor(node.parentNode);
|
||||
}
|
||||
|
||||
return <Element>node;
|
||||
}
|
||||
|
||||
getNodeAtPosition(position: Position): Node {
|
||||
return this._getNodeAtPositionCore(position, this._xmlDocument.documentElement);
|
||||
}
|
||||
|
||||
getSiblings(node: Node): Node[] {
|
||||
return [...this.getChildAttributeArray(<Element>node.parentNode), ...this.getChildElementArray(node.parentNode)];
|
||||
}
|
||||
|
||||
hasSimilarSiblings(node: Node): boolean {
|
||||
if (!node || !node.parentNode || !this.isElement(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const siblings = this.getChildElementArray(<Element>node.parentNode);
|
||||
|
||||
return (siblings.filter(x => x.tagName === (node as Element).tagName).length > 1);
|
||||
}
|
||||
|
||||
isElement(node: Node): boolean {
|
||||
return (!!node && !!(node as Element).tagName);
|
||||
}
|
||||
|
||||
private _getNodeAtPositionCore(position: Position, contextNode: Node): Node {
|
||||
if (!contextNode) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lineNumber = (contextNode as any).lineNumber;
|
||||
const columnNumber = (contextNode as any).columnNumber;
|
||||
const columnRange = [columnNumber, (columnNumber + (this._getNodeWidthInCharacters(contextNode) - 1))];
|
||||
|
||||
// for some reason, xmldom sets the column number for attributes to the "="
|
||||
if (!this.isElement(contextNode)) {
|
||||
columnRange[0] = (columnRange[0] - contextNode.nodeName.length);
|
||||
}
|
||||
|
||||
if (lineNumber === (position.line + 1) && ((position.character + 1) >= columnRange[0] && (position.character + 1) < columnRange[1])) {
|
||||
return contextNode;
|
||||
}
|
||||
|
||||
if (this.isElement(contextNode)) {
|
||||
const children = [...this.getChildAttributeArray(<Element>contextNode), ...this.getChildElementArray(contextNode)];
|
||||
let result: Node;
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
|
||||
result = this._getNodeAtPositionCore(position, child);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _getNodeWidthInCharacters(node: Node) {
|
||||
if (this.isElement(node)) {
|
||||
return (node.nodeName.length + 2);
|
||||
}
|
||||
|
||||
else {
|
||||
return (node.nodeName.length + node.nodeValue.length + 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue