使用 STX 解析器在 XML 中匹配两个不同的块

Matching two different blocks in XML using STX parser

提问人:srgplv 提问时间:6/18/2023 更新时间:6/18/2023 访问量:66

问:

我有一个大的XML文件,我正在尝试使用STX的java joost实现按id匹配两个块。这是我的XML文件:

<?xml version='1.0' encoding='UTF-8'?>
<main>
    <table>
        <description id="1" size="big" />
        <description id="2" size="small" />
        <description id="3" size="medium" />
    </table>
    <products>
        <item id="1" color="red" />
        <item id="2" color="green" />
        <item id="3" color="blue" />
    </products>
</main>

这是我尝试创建的输出:

<?xml version='1.0' encoding='UTF-8'?>
<total>
    <item id="1" color="red" size="big" />
    <item id="2" color="green" size="small" />
    <item id="3" color="blue" size="medium" />
</total>

没有给出任何结果,也没有创建类似于 java 的键值对的解决方案。有什么解决办法吗?stx:bufferHashMap

xml xslt xml 解析 stx

评论


答:

0赞 Martin Honnen 6/18/2023 #1

我不熟悉 STX,使用标准 XSLT 3.0 流,您可以使用保存地图的累加器:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:accumulator name="description" as="map(xs:untypedAtomic, xs:string)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="table/description" select="map:put($value, @id, string(@size))"/>
  </xsl:accumulator>

  <xsl:mode on-no-match="shallow-copy" use-accumulators="description" streamable="yes"/>

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:template match="main">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="table"/>
  <xsl:template match="products">
    <total>
      <xsl:apply-templates/>
    </total>
  </xsl:template>
  
  <xsl:template match="item">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="size" select="accumulator-before('description')(@id)"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

带有流的 XSLT 3.0 目前似乎只受 Saxon EE(9.8 及更高版本(即 9.9、10、11、12))支持。

我现在尝试构建一个 STX 示例,以下内容似乎有效:

<stx:transform xmlns:stx="http://stx.sourceforge.net/2002/ns" version="1.0"
               pass-through="all" strip-space="yes">

  <stx:variable name="id"/>
  <stx:variable name="size"/>

  <stx:template match="table/description">
    <stx:assign name="id" select="($id, string(@id))"/>
    <stx:assign name="size" select="($size, string(@size))"/>
  </stx:template>

  <stx:template match="/* | table | table/description">
    <stx:process-children/>
  </stx:template>

  <stx:template match="products">
    <total>
      <stx:process-children/>
    </total>
  </stx:template>

  <stx:template match="item">
    <stx:copy attributes="@*">
      <stx:attribute name="size" select="item-at($size, index-of($id, @id))"/>
    </stx:copy>
  </stx:template>

</stx:transform>

或者使用 Java HashMap:

<stx:transform xmlns:stx="http://stx.sourceforge.net/2002/ns" version="1.0"
               xmlns:hm="java:java.util.HashMap"
               exclude-result-prefixes="hm"
               pass-through="all" strip-space="no">

  <stx:variable name="description" select="hm:new()"/>

  <stx:template match="table/description">
    <stx:variable name="oldValue" select="hm:put($description, string(@id), string(@size))"/>
    <!-- <stx:assign name="description" select="$description"/> -->
  </stx:template>

  <stx:template match="/* | table | table/description">
    <stx:process-children/>
  </stx:template>

  <stx:template match="products">
    <total>
      <stx:process-children/>
    </total>
  </stx:template>

  <stx:template match="item">
    <stx:copy attributes="@*">
      <stx:attribute name="size" select="hm:get($description, string(@id))"/>
    </stx:copy>
  </stx:template>

</stx:transform>

评论

0赞 srgplv 6/18/2023
效果很好!谢谢!