GET 请求 XML 响应解析使用 XPath 生成 JS Object

GET Request XML response parsing using XPath to produce a JS Object

问题是我从对 WMS 服务器的 GET 请求得到“application/xml”响应,然后我使用 DOMParser().parseFromString() 方法使用 XPath 表达式进行解析。我尝试查看不同的解决方案,如专用库,但我发现了 XPath 表达式,现在我需要帮助编写一个 XPath 表达式,它将 return 我层标记的名称和 XML 响应的标题看起来喜欢

<Layer>
<Title>Title Level 1</Title>
<Name>Name Level 1</Name>
    <Layer>
    <Title>Title Level 2</Title>
    <Name>Name Level 2</Name>
        <Layer>
        <Title>Title Level 3-1</Title>
        <Name>Name Level 3-1</Name>
        </Layer>
        <Layer>
        <Title>Title Level 3-2</Title>
        <Name>Name Level 3-2</Name>
        </Layer>
    </Layer>
</Layer>

然后 return 我 JSON

{
title: 'Title Level 1'
name: 'Name Level 1'
children: [
    {
     title: 'Title Level 2'
     name: 'Name Level 2'
     children: [
         {
          title: 'Title Level 3-1'
          name: 'Name Level 3-1'
         },
         {
          title: 'Title Level 3-1'
          name: 'Name Level 3-1'
         }
     ]
]
}

您可以在浏览器中使用 XSLT 3 和 Saxon-JS 2 (https://www.saxonica.com/download/javascript.xml) 将 XML 转换为 JSON:

const xml = `<Layer>
<Title>Title Level 1</Title>
<Name>Name Level 1</Name>
    <Layer>
    <Title>Title Level 2</Title>
    <Name>Name Level 2</Name>
        <Layer>
        <Title>Title Level 3-1</Title>
        <Name>Name Level 3-1</Name>
        </Layer>
        <Layer>
        <Title>Title Level 3-2</Title>
        <Name>Name Level 3-2</Name>
        </Layer>
    </Layer>
</Layer>`;

const xslt = `<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:output method="json" build-tree="no"/>
  
  <xsl:template match="/*" priority="5">
    <xsl:variable name="json-xml">
      <map>
        <xsl:apply-templates/>
      </map>
    </xsl:variable>
    <xsl:sequence select="xml-to-json($json-xml) => parse-json()"/>
  </xsl:template>
  
  <xsl:template match="*[not(*)]">
    <string key="{local-name()}">{.}</string>
  </xsl:template>
  
  <xsl:template match="Layer[1]">
    <array key="children">
       <xsl:apply-templates select="../Layer" mode="map"/>
    </array>
  </xsl:template>
  
  <xsl:template match="Layer[position() > 1]"/>
  
  <xsl:template match="Layer" mode="map">
    <map>
      <xsl:apply-templates/>
    </map>
  </xsl:template>
  
</xsl:stylesheet>`;

const jsonResult = SaxonJS.XPath.evaluate(`transform(map { 'source-node' : parse-xml($xml), 'stylesheet-text' : $xslt, 'delivery-format' : 'raw' })?output`, [], { 'params' : { 'xml' : xml, 'xslt' : xslt } });

console.log(jsonResult);
<script src="https://xsltfiddle-beta.liberty-development.net/js/SaxonJS2/SaxonJS2.js"></script>

一种略有不同但可能更紧凑的 XSLT 3 方法是将 XML 直接转换为映射和数组输出作为 JSON 对象和数组:

const xml = `<Layer>
<Title>Title Level 1</Title>
<Name>Name Level 1</Name>
    <Layer>
    <Title>Title Level 2</Title>
    <Name>Name Level 2</Name>
        <Layer>
        <Title>Title Level 3-1</Title>
        <Name>Name Level 3-1</Name>
        </Layer>
        <Layer>
        <Title>Title Level 3-2</Title>
        <Name>Name Level 3-2</Name>
        </Layer>
    </Layer>
</Layer>`;

const xslt = `<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
   exclude-result-prefixes="#all"
   xmlns="http://www.w3.org/2005/xpath-functions"
   xmlns:mf="http://example.com/mf"
   expand-text="yes"
   version="3.0">
  
  <xsl:strip-space elements="*"/>

  <xsl:output method="json" build-tree="no" indent="yes"/>
  
  <xsl:template match="/Layer" priority="5">
<xsl:map>
  <xsl:apply-templates/>
</xsl:map>
  </xsl:template>
  
  <xsl:template match="*[not(*)]">
<xsl:map-entry key="local-name()" select="data()"/>
  </xsl:template>
  
  <xsl:template match="Layer[1]">
<xsl:map-entry key="'children'">
  <xsl:sequence select="array { ../Layer/mf:apply-templates(.) }"/>
</xsl:map-entry>
  </xsl:template>
  
  <xsl:template match="Layer[position() > 1]"/>
  
  <xsl:function name="mf:apply-templates" as="item()*">
<xsl:param name="elements" as="element(*)*"/>
<xsl:map>
  <xsl:apply-templates select="$elements/*"/>      
</xsl:map>
  </xsl:function>
  
</xsl:stylesheet>`;

const jsonResult = SaxonJS.XPath.evaluate(`
  transform(
    map { 
      'source-node' : parse-xml($xml), 
      'stylesheet-text' : $xslt, 
      'delivery-format' : 'raw' 
    }
  )?output`, 
  [], 
  { 'params' : { 'xml' : xml, 'xslt' : xslt } }
);

console.log(jsonResult);
<script src="https://xsltfiddle-beta.liberty-development.net/js/SaxonJS2/SaxonJS2.js"></script>

在两个示例中,为了简洁(以及可执行的单个 Whosebug 代码片段的优雅),我使用 XPath 3.1 transform 函数直接从 JavaScript 到 运行 XSLT 3 代码;虽然 Saxon-JS 2 在浏览器和 Node.js 中都完美支持,但应该注意的是,出于性能原因,如果您开发并修复了 XSLT,推荐的方法是使用 Saxon EE 进行预编译或使用 Saxon JS 2 的 xslt3 命令行从 XSLT 到 SEF(即从基于 XML 的 XSLT 代码到基于 JSON 的 SEF 格式)以便 SEF 可以直接馈送到 transform Saxon JS 中的函数 API https://www.saxonica.com/saxon-js/documentation/index.html#!api/transform。在现实世界中,这应该比使用 SaxonJS.XPath.evaluate 表现得更好,并且在 Node.js 上还允许您使用异步编程。