使用 Javascript DOM 解析器从 WMS GetCapabilities 请求的 XML response.data 中提取层列表
Posted
技术标签:
【中文标题】使用 Javascript DOM 解析器从 WMS GetCapabilities 请求的 XML response.data 中提取层列表【英文标题】:Using a Javascript DOM Parser extract the list of Layers from the XML response.data of an WMS GetCapabilities request 【发布时间】:2021-07-28 04:44:27 【问题描述】:我正在尝试提取 WMS 服务器可用层的名称列表。我已经为 GeoMet WMS 这样做了,方法是发送一个 GetCapabilities,它返回一个“应用程序/xml”对象,然后我使用 DOM 解析器进行解析。我的问题是图层标签嵌套在两个级别上。基本上顶层层包含多个子层。我将如何仅提取父层的子层或列表。通过意识到子节点具有父节点没有的属性,我设法解决了这个问题,但必须有更好的方法。
编辑:我有兴趣获取可以添加到交互式地图的完整图层列表。基本上所有没有图层子级的图层标签。
axios.get('https://geo.weather.gc.ca/geomet?lang=en&service=WMS&version=1.3.0&request=GetCapabilities').then((response) =>
// console.log(response.headers)
const parser = new DOMParser()
const dom = parser.parseFromString(response.data, 'application/xml')
let layerGroups = dom.querySelectorAll('[cascaded="0"]')
let layerNames = []
layerGroups.forEach(function (domel) layerNames.push(domel.getElementsByTagName('Name')[0].innerhtml) )
console.log(layerNames.length)
this.mylayerlist = layerNames
)
【问题讨论】:
你可以使用querySelectorAll('[cascaded="0"] name').map(node => node.innerHTML)
来简化它
您的问题不清楚 - 您是否对 CGSL.ETA_ICEC SEA_ICECONC-LINEAR, SEA_ICECONC, CGSL.ETA_ICEPRS
等名称感兴趣(其中有 12,470 个...)或其他名称?
@PhilipRollins 感谢您抽出宝贵时间,但不幸的是,这只是一个 hack,因为并非所有 WMS 都具有与 Layer 标签关联的属性。理想情况下,无论我查询哪个 WMS,我都会以这种方式获取所有没有图层子节点的图层节点,我将获得可添加到地图的图层的完整列表。
@JackFleeting 感谢您抽出宝贵时间,并对不完整的问题表示歉意。我的意思是说我想要任何给定 WMS 的所有层,或者换句话说,如果我传入一个 URL,我会得到没有层子节点的层节点的完整列表。是的 CGSL.ETA_ICEC 和其他。
【参考方案1】:
有几种方法可以处理这个问题,尤其是命名空间。这是其中之一。在你的 dom 声明之后试试这个:
xpath = '//*[local-name()="Layer"][@cascaded="0"][not(.//*[local-name()="Layer"])]/*[local-name()="Name"]';
var targets = dom.evaluate(xpath, dom, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
let nodes = Array.from( length: targets.snapshotLength , (_, index) =>
console.log(targets.snapshotItem(index).innerHTML));
输出是 3,519 个(在这种情况下)名称:
CGSL.ETA_ICEC
CGSL.ETA_ICEPRS
CGSL.ETA_ICESTG
CGSL.ETA_ICET
CGSL.ETA_ICETK
这里的关键组件是 xpath 表达式。它选择所有具有cascaded
属性且值为0
且没有Layer
子节点的Layer
节点。在这种特殊情况下,具有cascaded
属性的Layer
节点(请注意,所有这些属性都具有0
属性值)都没有Layer
子节点,因此您可以省去两个谓词之一([@cascaded="0"]
或 [not(./*[local-name()="Layer"])]
并获得相同的输出,但其他文件可能并非如此)。
【讨论】:
哇,非常感谢弗利廷先生。我将阅读 XPaths。只是为了确保我理解我会写 //*[local-name()="Layer"][not(.//*[local-name()="Layer"])]/*[local-name( )="Name"] 将返回所有没有 Layer 子节点的 Layer 或 Name 节点的列表? @YordanRadev 几乎:该表达式返回名为Name
的所有节点的集合,这些节点本身是名为 Layer
的节点的子节点,它们本身没有任何名为 Layer
的子节点。该集合是类数组,而不是数组。 Array.from
循环将集合转换为数组,并从每个数组元素(即每个 Name
节点)中提取内部 html/文本字符串,该字符串本身就是 Name
节点的实际名称。抱歉,这让您感到困惑,但无济于事......
谢谢先生。我会调查它,最终它不会像正则表达式那么糟糕。
@YordanRadev 这是我个人的看法,但我不得不说:没有什么比正则表达式更糟糕...以上是关于使用 Javascript DOM 解析器从 WMS GetCapabilities 请求的 XML response.data 中提取层列表的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 spark databricks xml 解析器从 Hdfs 目录加载所有 xml 文件