使用 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 中提取层列表的主要内容,如果未能解决你的问题,请参考以下文章

dom4j解析(利用迭代器从根节点遍历)

SAX 解析器从 endelement 获取属性

如何使用角度路径解析器从api解析数据

如何使用 spark databricks xml 解析器从 Hdfs 目录加载所有 xml 文件

ruby 使用AnyStyle解析器从剪贴板解析引用,并将相应的bibtex记录返回到剪贴板

如何让 SAX 解析器从 xml 声明中确定编码?