添加markdown解析器,以后使用markdown写帮助文档

This commit is contained in:
Antecer committed 2024-04-05 20:06:37 +08:00
1 parent e8df868b08
commit 89b7b71962
9 files changed
+1644 -8

No files matched your search

@@ -0,0 +1 @@
.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;margin:0;color:#24292f;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body .octicon{display:inline-block;fill:currentColor;vertical-align:text-bottom}.markdown-body h1:hover .anchor .octicon-link:before,.markdown-body h2:hover .anchor .octicon-link:before,.markdown-body h3:hover .anchor .octicon-link:before,.markdown-body h4:hover .anchor .octicon-link:before,.markdown-body h5:hover .anchor .octicon-link:before,.markdown-body h6:hover .anchor .octicon-link:before{width:16px;height:16px;content:' ';display:inline-block;background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>")}.markdown-body details,.markdown-body figcaption,.markdown-body figure{display:block}.markdown-body summary{display:list-item}.markdown-body [hidden]{display:none!important}.markdown-body a{background-color:transparent;color:#0969da;text-decoration:none}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body abbr[title]{border-bottom:none;text-decoration:underline dotted}.markdown-body b,.markdown-body strong{font-weight:600}.markdown-body dfn{font-style:italic}.markdown-body h1{margin:.67em 0;font-weight:600;padding-bottom:.3em;font-size:2em;border-bottom:1px solid #d7dde3}.markdown-body mark{background-color:#fff8c5;color:#24292f}.markdown-body small{font-size:90%}.markdown-body sub,.markdown-body sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.markdown-body sub{bottom:-.25em}.markdown-body sup{top:-.5em}.markdown-body img{border-style:none;max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body code,.markdown-body kbd,.markdown-body pre,.markdown-body samp{font-family:monospace,monospace;font-size:1em}.markdown-body figure{margin:1em 40px}.markdown-body hr{box-sizing:content-box;overflow:hidden;background:0 0;border-bottom:1px solid #d7dde3;height:.25em;padding:0;margin:24px 0;background-color:#d0d7de;border:0}.markdown-body input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body [type=button],.markdown-body [type=reset],.markdown-body [type=submit]{-webkit-appearance:button}.markdown-body [type=button]::-moz-focus-inner,.markdown-body [type=reset]::-moz-focus-inner,.markdown-body [type=submit]::-moz-focus-inner{border-style:none;padding:0}.markdown-body [type=button]:-moz-focusring,.markdown-body [type=reset]:-moz-focusring,.markdown-body [type=submit]:-moz-focusring{outline:1px dotted ButtonText}.markdown-body [type=checkbox],.markdown-body [type=radio]{box-sizing:border-box;padding:0}.markdown-body [type=number]::-webkit-inner-spin-button,.markdown-body [type=number]::-webkit-outer-spin-button{height:auto}.markdown-body [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.markdown-body [type=search]::-webkit-search-cancel-button,.markdown-body [type=search]::-webkit-search-decoration{-webkit-appearance:none}.markdown-body ::-webkit-input-placeholder{color:inherit;opacity:.54}.markdown-body ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.markdown-body a:hover{text-decoration:underline}.markdown-body hr::before{display:table;content:""}.markdown-body hr::after{display:table;clear:both;content:""}.markdown-body table{border-spacing:0;border-collapse:collapse;display:block;width:max-content;max-width:100%;overflow:auto}.markdown-body td,.markdown-body th{padding:0}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none!important}.markdown-body kbd{display:inline-block;padding:3px 5px;font:11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;line-height:10px;color:#24292f;vertical-align:middle;background-color:#f6f8fa;border:solid 1px rgba(175,184,193,.2);bordeLine truncated
+97
View File
@@ -0,0 +1,97 @@
/*
Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
*/
.hljs {
color: #abb2bf;
background: #282c34;
}
.hljs-keyword,
.hljs-operator {
color: #f92672;
}
.hljs-pattern-match {
color: #f92672;
}
.hljs-pattern-match .hljs-constructor {
color: #61aeee;
}
.hljs-function {
color: #61aeee;
}
.hljs-function .hljs-params {
color: #a6e22e;
}
.hljs-function .hljs-params .hljs-typing {
color: #fd971f;
}
.hljs-module-access .hljs-module {
color: #7e57c2;
}
.hljs-constructor {
color: #e2b93d;
}
.hljs-constructor .hljs-string {
color: #9ccc65;
}
.hljs-comment,
.hljs-quote {
color: #b18eb1;
font-style: italic;
}
.hljs-doctag,
.hljs-formula {
color: #c678dd;
}
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta .hljs-string {
color: #98c379;
}
.hljs-built_in,
.hljs-title.class_,
.hljs-class .hljs-title {
color: #e6c07b;
}
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #d19a66;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #61aeee;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>help</title>
<link rel="stylesheet" href="css/github-markdown-light.min.css" />
<link rel="stylesheet" href="css/highlight.min.css" />
<style>
body {
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
</style>
<script src="js/require.js" data-main="js/main" defer async="true"></script>
</head>
<body>
<div id="mdviewer" class="markdown-body"></div>
</body>
</html>
File diff suppressed because it is too large. Load diff
+38
View File
@@ -0,0 +1,38 @@
require.config({
baseUrl: 'js',
paths: {
markdownit: 'markdown-it.min',
highlight: 'highlight.min',
},
shim: {
highlight: {
exports: 'hljs',
},
},
});
require(['markdownit', 'highlight'], (mdit, hljs) => {
const md = mdit({
html: false, // 在源代码中启用 HTML 标签
xhtmlOut: false, // 使用“/”关闭单个标签 (<br />)。 这仅用于完全兼容 CommonMark。
breaks: false, // 将段落中的 '\n' 转换为 <br>
langPrefix: 'language-', // 代码块的 CSS 属性前缀。用于代码高亮插件。
linkify: false, // 自动将类似 URL 的文本转换为链接
typographer: false, // 启用一些语言中立的替换+引号美化
quotes: '“”‘’',
highlight: function (code, lang) {
let language = hljs.getLanguage(lang)?.name ?? 'plaintext';
if (language.includes('HTML')) language = 'xml';
return hljs.highlight(code, {language}).value;
},
});
const path = '../md/';
const file = location.hash.slice(1).trim();
if (!file) return;
fetch(`${path}${file}.md`)
.then((response) => response.text())
.then((md_text) => {
document.getElementById('mdviewer').innerHTML = md.render(md_text);
});
});
+2
View File
@@ -0,0 +1,2 @@
/*! markdown-it 14.1.0 https://github.com/markdown-it/markdown-it @license MIT */
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).markdownit=e()}(this,(function(){"use strict";const t={};function e(r,n){"string"!=typeof n&&(n=e.defaultChars);const s=function(e){let r=t[e];if(r)return r;r=t[e]=[];for(let t=0;t<128;t++){const e=String.fromCharCode(t);r.push(e)}for(let t=0;t<e.length;t++){const n=e.charCodeAt(t);r[n]="%"+("0"+n.toString(16).toUpperCase()).slice(-2)}return r}(n);return r.replace(/(%[a-f0-9]{2})+/gi,(function(t){let e="";for(let r=0,n=t.length;r<n;r+=3){const i=parseInt(t.slice(r+1,r+3),16);if(i<128)e+=s[i];else{if(192==(224&i)&&r+3<n){const n=parseInt(t.slice(r+4,r+6),16);if(128==(192&n)){const t=i<<6&1984|63&n;e+=t<128?"\ufffd\ufffd":String.fromCharCode(t),r+=3;continue}}if(224==(240&i)&&r+6<n){const n=parseInt(t.slice(r+4,r+6),16),s=parseInt(t.slice(r+7,r+9),16);if(128==(192&n)&&128==(192&s)){const t=i<<12&61440|n<<6&4032|63&s;e+=t<2048||t>=55296&&t<=57343?"\ufffd\ufffd\ufffd":String.fromCharCode(t),r+=6;continue}}if(240==(248&i)&&r+9<n){const n=parseInt(t.slice(r+4,r+6),16),s=parseInt(t.slice(r+7,r+9),16),o=parseInt(t.slice(r+10,r+12),16);if(128==(192&n)&&128==(192&s)&&128==(192&o)){let t=i<<18&1835008|n<<12&258048|s<<6&4032|63&o;t<65536||t>1114111?e+="\ufffd\ufffd\ufffd\ufffd":(t-=65536,e+=String.fromCharCode(55296+(t>>10),56320+(1023&t))),r+=9;continue}}e+="\ufffd"}}return e}))}e.defaultChars=";/?:@&=+$,#",e.componentChars="";const r={};function n(t,e,s){"string"!=typeof e&&(s=e,e=n.defaultChars),void 0===s&&(s=!0);const i=function(t){let e=r[t];if(e)return e;e=r[t]=[];for(let t=0;t<128;t++){const r=String.fromCharCode(t);/^[0-9a-z]$/i.test(r)?e.push(r):e.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2))}for(let r=0;r<t.length;r++)e[t.charCodeAt(r)]=t[r];return e}(e);let o="";for(let e=0,r=t.length;e<r;e++){const n=t.charCodeAt(e);if(s&&37===n&&e+2<r&&/^[0-9a-f]{2}$/i.test(t.slice(e+1,e+3)))o+=t.slice(e,e+3),e+=2;else if(n<128)o+=i[n];else if(n>=55296&&n<=57343){if(n>=55296&&n<=56319&&e+1<r){const r=t.charCodeAt(e+1);if(r>=56320&&r<=57343){o+=encodeURIComponent(t[e]+t[e+1]),e++;continue}}o+="%EF%BF%BD"}else o+=encodeURIComponent(t[e])}return o}function s(t){let e="";return e+=t.protocol||"",e+=t.slashes?"//":"",e+=t.auth?t.auth+"@":"",t.hostname&&-1!==t.hostname.indexOf(":")?e+="["+t.hostname+"]":e+=t.hostname||"",e+=t.port?":"+t.port:"",e+=t.pathname||"",e+=t.search||"",e+=t.hash||"",e}function i(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}n.defaultChars=";/?:@&=+$,-_.!~*'()#",n.componentChars="-_.!~*'()";const o=/^([a-z0-9.+-]+:)/i,u=/:[0-9]*$/,c=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,a=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(a),h=["%","/","?",";","#"].concat(l),p=["/","?","#"],f=/^[+a-z0-9A-Z_-]{0,63}$/,d=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,_={javascript:!0,"javascript:":!0},m={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};function g(t,e){if(t&&t instanceof i)return t;const r=new i;return r.parse(t,e),r}i.prototype.parse=function(t,e){let r,n,s,i=t;if(i=i.trim(),!e&&1===t.split("#").length){const t=c.exec(i);if(t)return this.pathname=t[1],t[2]&&(this.search=t[2]),this}let u=o.exec(i);if(u&&(u=u[0],r=u.toLowerCase(),this.protocol=u,i=i.substr(u.length)),(e||u||i.match(/^\/\/[^@\/]+@[^@\/]+/))&&(s="//"===i.substr(0,2),!s||u&&_[u]||(i=i.substr(2),this.slashes=!0)),!_[u]&&(s||u&&!m[u])){let t,e,r=-1;for(let t=0;t<p.length;t++)n=i.indexOf(p[t]),-1!==n&&(-1===r||n<r)&&(r=n);e=-1===r?i.lastIndexOf("@"):i.lastIndexOf("@",r),-1!==e&&(t=i.slice(0,e),i=i.slice(e+1),this.auth=t),r=-1;for(let t=0;t<h.length;t++)n=i.indexOf(h[t]),-1!==n&&(-1===r||n<r)&&(r=n);-1===r&&(r=i.length),":"===i[r-1]&&r--;const s=i.slice(0,r);i=i.slice(r),this.parseHost(s),this.hostname=this.hostname||"";const o="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!o){const t=this.hostname.split(/\./);for(let e=0,r=t.length;e<r;e++){const r=t[e];if(r&&!r.match(f)){let n="";for(let t=0,e=r.length;t<e;t++)r.charCodeAt(t)>127?n+="x":n+=r[t];if(!n.match(f)){const n=t.slice(0,e),s=t.slice(e+1),o=r.match(d);o&&(n.push(o[1]),s.unshift(o[2])),s.length&&(i=s.join(".")+i),this.hostname=n.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),o&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}const a=i.indexOf("#");-1!==a&&(this.hash=i.substr(a),i=i.slice(0,a));const l=i.indexOf("?");return-1!==l&&(this.search=i.substr(l),i=i.slice(0,l)),i&&(this.pathname=i),m[r]&&this.hostname&&!this.pathname&&(this.pathname=""),this},i.prototype.parseHost=function(t){let e=u.exec(t);e&&(e=e[0],":"!==e&&(this.port=e.substr(1)),t=t.substr(0,t.length-e.length)),t&&(this.hostname=t)};var k,D=Object.freeze({__proto__:null,decode:e,encode:n,format:s,parse:g}),C=/[\0-Line truncated
@@ -0,0 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors.
* Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
*/
var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;i<e.length&&(!e[i]||!t(e[i],i,e));i+=1);}function eachReverse(e,t){var i;if(e)for(i=e.length-1;-1<i&&(!e[i]||!t(e[i],i,e));i-=1);}function hasProp(e,t){return hasOwn.call(e,t)}function getOwn(e,t){return hasProp(e,t)&&e[t]}function eachProp(e,t){var i;for(i in e)if(hasProp(e,i)&&t(e[i],i))break}function mixin(i,e,r,n){return e&&eachProp(e,function(e,t){!r&&hasProp(i,t)||(!n||"object"!=typeof e||!e||isArray(e)||isFunction(e)||e instanceof RegExp?i[t]=e:(i[t]||(i[t]={}),mixin(i[t],e,r,n)))}),i}function bind(e,t){return function(){return t.apply(e,arguments)}}function scripts(){return document.getElementsByTagName("script")}function defaultOnError(e){throw e}function getGlobal(e){if(!e)return e;var t=global;return each(e.split("."),function(e){t=t[e]}),t}function makeError(e,t,i,r){var n=new Error(t+"\nhttps://requirejs.org/docs/errors.html#"+e);return n.requireType=e,n.requireModules=r,i&&(n.originalError=i),n}if(void 0===define){if(void 0!==requirejs){if(isFunction(requirejs))return;cfg=requirejs,requirejs=void 0}void 0===require||isFunction(require)||(cfg=require,require=void 0),req=requirejs=function(e,t,i,r){var n,o,a=defContextName;return isArray(e)||"string"==typeof e||(o=e,isArray(t)?(e=t,t=i,i=r):e=[]),o&&o.context&&(a=o.context),(n=getOwn(contexts,a))||(n=contexts[a]=req.s.newContext(a)),o&&n.configure(o),n.require(e,t,i)},req.config=function(e){return req(e)},req.nextTick=void 0!==setTimeout?function(e){setTimeout(e,4)}:function(e){e()},require||(require=req),req.version=version,req.jsExtRegExp=/^\/|:|\?|\.js$/,req.isBrowser=isBrowser,s=req.s={contexts:contexts,newContext:newContext},req({}),each(["toUrl","undef","defined","specified"],function(t){req[t]=function(){var e=contexts[defContextName];return e.require[t].apply(e,arguments)}}),isBrowser&&(head=s.head=document.getElementsByTagName("head")[0],baseElement=document.getElementsByTagName("base")[0],baseElement&&(head=s.head=baseElement.parentNode)),req.onError=defaultOnError,req.createNode=function(e,t,i){var r=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");return r.type=e.scriptType||"text/javascript",r.charset="utf-8",r.async=!0,r},req.load=function(t,i,r){var e,n=t&&t.config||{};if(isBrowser)return(e=req.createNode(n,i,r)).setAttribute("data-requirecontext",t.contextName),e.setAttribute("data-requiremodule",i),!e.attachEvent||e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0||isOpera?(e.addEventListener("load",t.onScriptLoad,!1),e.addEventListener("error",t.onScriptError,!1)):(useInteractive=!0,e.attachEvent("onreadystatechange",t.onScriptLoad)),e.src=r,n.onNodeCreated&&n.onNodeCreated(e,n,i,r),currentlyAddingScript=e,baseElement?head.insertBefore(e,baseElement):head.appendChild(e),currentlyAddingScript=null,e;if(isWebWorker)try{setTimeout(function(){},0),importScripts(r),t.completeLoad(i)}catch(e){t.onError(makeError("importscripts","importScripts failed for "+i+" at "+r,e,[i]))}},isBrowser&&!cfg.skipDataMain&&eachReverse(scripts(),function(e){if(head||(head=e.parentNode),dataMain=e.getAttribute("data-main"))return mainScript=dataMain,cfg.baseUrl||-1!==mainScript.indexOf("!")||(mainScript=(src=mainScript.split("/")).pop(),subPath=src.length?src.join("/")+"/":"./",cfg.baseUrl=subPath),mainScript=mainScript.replace(jsSuffixRegExp,""),req.jsExtRegExp.test(mainScript)&&(mainScript=dataMain),cfg.deps=cfg.deps?cfg.deps.concat(mainScript):[mainScript],!0}),define=function(e,i,t){var r,n;"string"!=typeof e&&(t=i,i=e,e=null),isArray(i)||(t=i,i=null),!i&&isFunction(t)&&(i=[],t.length&&(t.toString().replace(commentRegExp,commentReplace).replace(cjsRequireRegExp,function(e,t){i.push(t)}),i=(1===t.length?["require"]:["require","exports","module"]).concat(i))),useInteractive&&(r=currentlyAddingScript||getInteractiveScript())&&(e||(e=r.getAttribute("data-requiremodule")),n=contexts[r.getAttribute("data-requirecontext")]),n?(n.defQueue.push([e,i,t]),n.defQueueMap[e]=!0):globalDefQueue.pushLine truncated
+265
View File
@@ -0,0 +1,265 @@
# xpath 路径表达式详解
_注:本文所有代码均通过 Chrome(版本 123.0.6312.86) 验证_
> XPath 规范中定义了 13 种不同的轴(axes)。
> 轴表示与元素的关系,并用于定位元素树上相对于该元素的元素。
- `namespace`(不支持)
- `attribute` 元素的属性。它可以缩写为 `@`
- `self` 表示元素本身。它可以缩写为 `.`
- `parent` 当前元素的父元素。它可以缩写为 `..`
- `child` 当前元素的子元素。
- `ancestor` 当前元素的所有直属祖先。
- `ancestor-or-self` 当前元素及其所有直属祖先。
- `descendant` 当前元素的所有递归子元素。
- `descendant-or-self` 当前元素及其所有递归子元素。
- `following` 当前元素之后出现的所有元素。无视元素层级,但不含直属后代。
- `following-sibling` 当前元素之后出现的所有同级元素。
- `preceding` 当前元素之前出现的所有元素。无视元素层级,但不含直属祖先。
- `preceding-sibling` 当前元素之前出现的所有同级元素。
```js
// 轴的用法-> 轴名::表达式
// 例:
> $x('//body/ancestor-or-self::*')
< [body, html]
```
#### 一、xpath 表达式的基本格式
> xpath 通过"路径表达式"(Path Expression)来选取元素。
> 在形式上,"路径表达式"与传统的文件系统非常类似。
```
# "/"斜杠作为路径内部的分割符。
# 同一个元素有绝对路径和相对路径两种写法。
# 绝对路径必须用"/"起首,后面紧跟根元素,比如/step/step/...。
# 相对路径则是除了绝对路径以外的其他写法,比如 step/step,也就是不使用"/"起首。
# "."表示当前元素。
# ".."表示当前元素的父元素
```
### 二、选取元素的基本规则
```
- "/":表示选取根元素
- "//":表示选取任意位置的某个元素
- nodename:表示选指定名称的元素
- "@": 表示选取某个属性
```
### 三、选取元素的实例
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>标题</title>
<meta property=author" content="作者" />
</head>
<body>
<div>
<title lang="eng">Harry Potter</title>
<p>29.39</p>
<p>usd</p>
</div>
<div>
<title lang="cn">Cpp高级编程</title>
<p>39.95</p>
<p>rmb</p>
</div>
<div id="list">
<dl>
<dd><a href="/1">一</a></dd>
<dd><a href="/2">二</a></dd>
<dd><a href="/3">三</a></dd>
</dl>
</div>
</body>
</html>
```
```js
// 例1
> $x('/') // 选取根元素,返回包含被选中元素的数组。
< [document]
// 例2
> $x('/html') // 选取根元素下的所有 html 子元素,这是绝对路径写法。
< [html]
// 例3
> $x('html/head/meta') // 选取 head 元素下的所有 meta 元素,这是相对路径写法。
< [meta, meta] // <meta charset="utf-8">, <meta property="author" content="作者">
// 例4
> $x('//p') // 选取所有 p 元素,不管它们在哪里
< [p, p, p, p] // <p>29.39</p>, <p>usd</p>, <p>39.95</p>, <p>rmb</p>
// 例5
> $x('html/body//a') // 选取 body 元素下的所有 a 元素
< [a, a, a] // <a href="/1">一</a>, <a href="/2">二</a>, <a href="/3">三</a>
// 例6
> $x('//@lang') // 选取所有名为 lang 的属性。
< [lang, lang] // lang="eng", lang="cn"
> $x('html/head/meta/@content') // 选取 head 元素下所有 meta 元素的 content 属性。
< [content] // content="作者"
// 例7
> $x('//meta/..') // 选取所有 meta 元素的父元素。(相同的结果只会返回一个)
< [head] // <head>...</head>
```
### 四、xpath 的谓语条件(Predicate)
> 所谓"谓语条件",就是对路径表达式的附加条件。
> 所有的附加条件,都写在方括号 `[]` 中,用于对元素进一步的筛选。
> 方括号内的表达式结果为 true 的元素才会被选取。
```js
// 例8
> $x('html/head/meta[1]') // 选取 head 元素下的第一个 meta 元素
< [meta] // <meta charset="utf-8">
> $x('//p[1]') // 选取所有元素下的第一个 p 元素
< [p, p] // <p>29.39</p>, <p>39.95</p>
// 例9
> $x('html/head/meta[last()]') // 选取 head 元素下的最后一个 meta 元素
< [meta] // <meta property="author" content="作者">
// 例10
> $x('html/head/meta[last()-1]') // 选取 head 元素下的倒数第二个 meta 元素
< [meta] // <meta charset="utf-8">
// 例11
> $x('html/head/meta[position()>1]') // 选取 head 元素下的除了第一个元素外的所有 meta 元素
< [meta] // <meta property="author" content="作者">
// 例12
> $x('//title[@lang]') // 选取所有具有lang属性的title元素。
< [title, title] // <title lang="eng">Harry Potter</title>, <title lang="cn">Cpp高级编程</title>
// 例13
> $x('//title[@lang="eng"]') // 选取所有lang属性的值等于"eng"的title元素。
< [title] // <title lang="eng">Harry Potter</title>
// 例14
> $x('/html/body/div[dl]') // 选择 body 的 div 子元素,且被选中 的 div 元素必须带有 dl 子元素。
< [div] // <div id="list"><dl id="list">...</dl></div>
// 例15
> $x('/html/body/div[p>35.00]') // 选取 body 的 div 子元素,且被选中 div 元素的 p 子元素的值必须大于 35.00。
< [div] // <div><title lang="cn">Cpp高级编程</title><p>39.95</p><p>rmb</p></div>
> $x('/html/body/div[p="rmb"]') // 选取 body 的 div 子元素,且被选中 div 元素的 p 子元素的值必须等于 "rmb"。
< [div] // <div><title lang="cn">Cpp高级编程</title><p>39.95</p><p>rmb</p></div>
// 例16
> $x('/html/body/div[p="rmb"]/title') // 在例14结果集中,选择title子元素。
< [title] // <title lang="cn">Cpp高级编程</title>
// 例17
> $x('/html/body/div/p[.>35.00]') // 选择值大于 35.00 的 "/html/body/div" 的 p 子元素。
< [p] // <p>39.95</p>
```
### 五、通配符
- `\*` 表示匹配任何元素。
- `@\*` 表示匹配任何属性名。
```js
// 例18
> $x('//*') // 选取所有元素,结果以递归顺序返回
< [html, head, meta, title, meta, body, div, title, p, p, div, title, p, p, div, dl, dd, a, dd, a, dd, a]
// 例19
> $x('/*/*') // 选取所有第二层的元素
< [head, body] // <head>...</head>, <body>...</body>
// 例20
> $x('//dl[@id="list"]/*') // 选取 id="list" 的 dl 元素的所有子元素。
< [dd, dd, dd] // <dd><a href="/1">一</a></dd>, <dd><a href="/2">二</a></dd>, <dd><a href="/3">三</a></dd>
// 例21
> $x('//title[@*]') // 选取所有带有属性的 title 元素。
< [title, title] // <title lang="eng">Harry Potter</title>, <title lang="cn">Cpp高级编程</title>
```
### 六、选择多个路径
- 用 `|` 合并多个表达式的选取结果。
```js
// 例22
> $x('//title | //a') // 选取所有 title 和 a 元素。
< [title, title, title, a, a, a]
```
### 七、xpath 的函数
> xpath 函数的参数可以是静态字符串或表达式,且函数可以嵌套调用。
> xpath 的索引均从1开始,而不是从0开始。
```js
// boolean(expression) 将表达式选取的结果转换为布尔值。
> $x('boolean(//title)')
< true
// number([object]) 将表达式选取的结果转换为数字。(HTML元素内容默认均为字符串)
> $x('number(//p[1])')
< 29.39
// round(decimal) 将数字参数转换为整数并四舍五入。
> $x('round(//p[1])')
< 29
// ceiling(number) 将数字参数转换为整数并向上取整。ceiling(5.2)=6
> $x('ceiling(//p[1])') // 仅使用匹配表达式的第一个元素
< 30
// floor(number) 将数字参数转换为整数并向下取整。floor(5.8)=5
> $x('floor(//p[1])')
< 29
// concat( string1, string2 [,stringn]* ) 字符串拼接,参数为静态字符串或表达式
> $x('concat("cost:", //p[1], //p[2])') // 仅使用匹配表达式的第一个元素
< 'cost:29.39usd'
// contains(haystack, needle) 判断 haystack 是否包含 needle,返回 boolean
> $x('contains(//p[1], "29.39")') // 仅使用匹配表达式的第一个元素
< true
> $x('//title[contains(., "Harry")]') // 选取内容中包含 "Harry" 的 title 元素。
< [title] // <title lang="eng">Harry Potter</title>
// count( node-set ) 统计表达式选取的元素个数。
> $x('count(//p)')
< 4
// id(expression) 根据 id 属性选取元素,若参数为表达式,将获取表达式结果作为id查询。
> $x('id(//dl/@id)') // 等效于 $x('id("list")')
< [dl#list] // <dl id="list">...</dl>
// last() 返回当前路径表达式匹配的同级元素集合的成员数量。
> $x('//p[last()]')
< [p, p] // <p>usd</p>, <p>rmb</p>
// name([node-set]) 返回表达式选取集合的首个成员带命名空间的元素名,HTML中与local-name([node-set])等价。
// local-name([node-set]) 返回表达式选取集合的首个成员本地元素名。
> $x('local-name(//*[@id])') //
< 'dl'
// namespace-uri([node-set]) 获取选定节点集中第一个节点的命名空间URI。
> $x('namespace-uri(//div)')
< 'http://www.w3.org/1999/xhtml' // HTML通常都返回这个固定值
// normalize-space([string]) 去文本内容中的前后空白以及将内部连续的空白替换为单个空格
> $x('normalize-space(" test string ")')
< 'test string'
// not(expression) 返回表达式的布尔反值。
> $x('//title[not(@lang)]')
< [title] // <title>标题</title>
// position() 返回选定元素处于路径表达式匹配的同级元素集合中的位置。
> $x('//meta[position()=2]')
< [meta] // <meta property=author" content="作者" />
// starts-with(haystack, needle) 检查某个字符串 haystack 是否以另一个字符串 needle 开始。
> $x('//title[starts-with(., "Cpp")]')
< [title] // <title lang="cn">Cpp高级编程</title]
// string([object]) 将给定参数转换为字符串
> $x('string(//p)')
< '29.39'
// string-length([string]) 返回给定字符串的字符数量
> $x('string-length(string(//p))')
< 5
// substring(string, start[, length]) 截取字符串
> $x('substring(string(//p), 1, 3)')
< '29.'
// substring-after(haystack, needle) 返回字符串 haystack 中第一个 needle 之后的字符串。
> $x('substring-after(string(//p), ".")')
< '39'
// substring-before(haystack, needle) 返回字符串 haystack 中第一个 needle 之前的字符串。
> $x('substring-before(string(//p), ".")')
< '29'
// sum([node-set]) 对给定集合的数字求和。若给定集合中存在非数字,则返回 NaN
> $x('sum(//p[1])')
< 69.34
// translate(string, "abc", "XYZ") 依次替换 string 中出现的 a、b、c 为对应位置的 X、Y、Z。
// 若第三个参数中的字符少于第二个参数,那么在第一个参数中相应的字符将被删除。
> $x('translate("aabbcc112233", "ac2", "V8")')
< 'VVbb881133'
// true() 表示函数中的 true 布尔值
// false() 表示函数中的 false 布尔值
```