代码之家  ›  专栏  ›  技术社区  ›  Reto

XSLT 3.0突发流-如何存储/获取另一个分支的值

  •  0
  • Reto  · 技术社区  · 6 月前

    我们正在使用Saxon EE 12.x将大型(多GB)XML文件转换为更小的内部XML结构。我们希望减少内存消耗和每个设备上的突发流 <Document> -节点似乎与我们的应用程序完美匹配。它确实有效,但我们很难理解一些看似简单的构造:如何获取像 <PrintDate> <ExportHeader> -分支并将其添加到每个输出中 <Doc> -元素作为流模式中的属性?

    源XML包含1000个 <文档> -节点,每个 <文档> -节点包含1000行XML <ExportHeader> -节点很小,只包含一些元信息。一个简化的源XML示例如下:

    <Export>
      <ExportHeader>
        <PrintDate>2024-12-24</PrintDate>
      </ExportHeader>
      <ExportContent>
        <Document>
          <LotsOfXml></LotsOfXml>
        </Document>
        <Document>
          <LotsOfXml></LotsOfXml>
        </Document>
        <Document>
          <LotsOfXml></LotsOfXml>
        </Document>
      </ExportContent>
    </Export>
    

    我们的目标XML应该如下所示:

    <Exp>
      <Doc PrintDate="???">
        <LotsOfTransformedXML></LotsOfTransformedXML>
      </Doc>
      <Doc PrintDate="???">
        <LotsOfTransformedXML></LotsOfTransformedXML>
      </Doc>
      <Doc PrintDate="???">
        <LotsOfTransformedXML></LotsOfTransformedXML>
      </Doc>
    </Exp>
    

    一个非常简单的XSLT看起来像这样,但我们不知道如何获得 <打印日期> 进入 <Doc> -节点属性,不破坏流化能力。。。能不能 <xsl:accumulator> 用于存储/获取值,如果是,如何操作?

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:math="http://www.w3.org/2005/xpath-functions/math"
      exclude-result-prefixes="xs math"
      version="3.0">
      
      <xsl:mode streamable="yes" on-no-match="shallow-skip"/>
      <xsl:mode name="insideDoc" streamable="no" on-no-match="shallow-copy "/>
      
      <xsl:template match="Export">
        <xsl:element name="Exp">
          <xsl:apply-templates></xsl:apply-templates>
        </xsl:element>
      </xsl:template>
      
        <xsl:template match="PrintDate">
          <!-- how to keep/store this PrintDate, so we can add it to the Doc elements as an attribute later... -->
        </xsl:template>
    
      <xsl:template match="ExportContent">
        <xsl:apply-templates select="copy-of(Document)" mode="insideDoc"/>
      </xsl:template>
      
      <xsl:template match="Document" mode="insideDoc">
        <xsl:element name="Doc">
          <xsl:attribute name="PrintDate" select="'???'"/>
          <xsl:apply-templates select="*" mode="insideDoc"/>      
        </xsl:element>
      </xsl:template>
      
      <xsl:template match="LotsOfXml" mode="insideDoc">
        <xsl:element name="LotsOfTransformedXML">
        </xsl:element>
      </xsl:template>
      
    </xsl:stylesheet>
    
    1 回复  |  直到 6 月前
        1
  •  1
  •   Martin Honnen    6 月前

    使用捕捉蓄能器 https://www.saxonica.com/html/documentation12/extensions/attributes/capture.html 例如

    <xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="PrintDate"/>
    
    <xsl:accumulator name="PrintDate" as="element(PrintDate)*" initial-value="()" streamable="yes">
      <xsl:accumulator-rule saxon:capture="yes" match="ExportHeader/PrintDate"
        phase="end" select="$value, ."/>
    </xsl:accumulator>
    

    声明 xmlns:saxon="http://saxon.sf.net/" . ...

    <xsl:attribute name="PrintDate" select="accumulator-before('PrintDate')"/>