按记录/阈值和复制标头的数量拆分 XML 文件 - XSLT 1.0

发布于 2024-11-04 19:10:41 字数 2933 浏览 1 评论 0原文

我有以下 XML 结构

<?xml version="1.0" encoding="UTF-8"?>
<ExportData>
<TransportHeader>
    <Timestamp>2011-01-16 06:00:33</Timestamp>
    <From>
        <Name>DynamicExport</Name>
        <Version>1.</Version>
    </From>
    <MessageId>d7b5c5b69a83</MessageId>
</TransportHeader>
<ExportConfig>
    <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
    <DecimalSymbol>.</DecimalSymbol>
</ExportConfig>
<DataSet> 
    <Tables>
        <Table>
            <RH>...</RH>
            <Rows>  
                <R>Data1</R>
                <R>Data2</R>
                <R>Data3</R>
                <R>Data4</R>
                <R>Data5</R>
            </Rows>
        </Table>
    </Tables>
</DataSet>
</ExportData>

,我需要根据 元素的数量拆分文件。 如果有超过 3 个 元素,则需要生成第二个输出文件。这两个文件还需要标头信息。

我想出了这个 XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:redirect="http://xml.apache.org/xalan/redirect"
extension-element-prefixes="redirect"
exclude-result-prefixes="xd"
version="1.0">

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="text() | @*"/>

<xsl:template match="Rows" name="Rows"> 
    <Rows>    
        <xsl:for-each select="R">
            <xsl:variable name="filename1" select="concat('output1','.xml')"/>
            <xsl:variable name="filename2" select="concat('output2','.xml')"/>
            <xsl:variable name="nodePosition" select="position()" />
            <xsl:if test="$nodePosition &lt; 3">
                <redirect:write select="$filename1">
                    <xsl:copy-of select="." />
                </redirect:write>
            </xsl:if>
            <xsl:if test="$nodePosition = 3 or $nodePosition &gt; 3">
                <redirect:write select="$filename2">
                        <xsl:copy-of select="." />
                </redirect:write> 
            </xsl:if>
        </xsl:for-each>  
    </Rows>        
</xsl:template>
</xsl:stylesheet>

但是生成的两个输出文件仅包含“Data2”和“Data5”。 您能帮我找出为什么其他 3 个数据元素丢失吗? 以及如何添加标题数据?

对于标题,我想出了这个 XSLT:

<xsl:template match="//Rows">
    <xsl:apply-templates select="@*|Rows"/>
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

当我将它应用于提到的 XML 时,它就起作用了。但我无法合并 2 个 XSLT - 输出变得混乱。

I have the following XML structure

<?xml version="1.0" encoding="UTF-8"?>
<ExportData>
<TransportHeader>
    <Timestamp>2011-01-16 06:00:33</Timestamp>
    <From>
        <Name>DynamicExport</Name>
        <Version>1.</Version>
    </From>
    <MessageId>d7b5c5b69a83</MessageId>
</TransportHeader>
<ExportConfig>
    <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
    <DecimalSymbol>.</DecimalSymbol>
</ExportConfig>
<DataSet> 
    <Tables>
        <Table>
            <RH>...</RH>
            <Rows>  
                <R>Data1</R>
                <R>Data2</R>
                <R>Data3</R>
                <R>Data4</R>
                <R>Data5</R>
            </Rows>
        </Table>
    </Tables>
</DataSet>
</ExportData>

and I need to split the file depending on the amounts of <R>elements.
If there are more than 3 <R> elements a second output file needs to be generated. Both files also need the header info.

I came up with this XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:redirect="http://xml.apache.org/xalan/redirect"
extension-element-prefixes="redirect"
exclude-result-prefixes="xd"
version="1.0">

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="text() | @*"/>

<xsl:template match="Rows" name="Rows"> 
    <Rows>    
        <xsl:for-each select="R">
            <xsl:variable name="filename1" select="concat('output1','.xml')"/>
            <xsl:variable name="filename2" select="concat('output2','.xml')"/>
            <xsl:variable name="nodePosition" select="position()" />
            <xsl:if test="$nodePosition < 3">
                <redirect:write select="$filename1">
                    <xsl:copy-of select="." />
                </redirect:write>
            </xsl:if>
            <xsl:if test="$nodePosition = 3 or $nodePosition > 3">
                <redirect:write select="$filename2">
                        <xsl:copy-of select="." />
                </redirect:write> 
            </xsl:if>
        </xsl:for-each>  
    </Rows>        
</xsl:template>
</xsl:stylesheet>

But the two output files that get generated only contain "Data2" and "Data5".
Could you help me figuring out why the other 3 data elements are missing?
And how can I add the header data?

For the header I came up with this XSLT:

<xsl:template match="//Rows">
    <xsl:apply-templates select="@*|Rows"/>
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

which works when I apply it to the XML mentioned. But I could not combine the 2 XSLTs - the output just gets messed up.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

清醇 2024-11-11 19:10:41

此转换显示了如何进行拆分。留下它作为练习,以适应您的需求:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="R[position() mod 3 =1]">
  <RGroup>
   <xsl:copy-of select=
    ".|following-sibling::R[not(position() > 2)]"/>
  </RGroup>
 </xsl:template>

 <xsl:template match="R"/>
</xsl:stylesheet>

当应用于此 XML 文档时(最初提供的文档的片段):

<Rows>
    <R>Data1</R>
    <R>Data2</R>
    <R>Data3</R>
    <R>Data4</R>
    <R>Data5</R>
</Rows>

生成所需的拆分:

<Rows>
   <RGroup>
      <R>Data1</R>
      <R>Data2</R>
      <R>Data3</R>
   </RGroup>
   <RGroup>
      <R>Data4</R>
      <R>Data5</R>
   </RGroup>
</Rows>

This transformation shows how to do the splitting. It is left as an exercise to adapt it to your needs:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="R[position() mod 3 =1]">
  <RGroup>
   <xsl:copy-of select=
    ".|following-sibling::R[not(position() > 2)]"/>
  </RGroup>
 </xsl:template>

 <xsl:template match="R"/>
</xsl:stylesheet>

When applied on this XML document (a fragment of the originally provided one):

<Rows>
    <R>Data1</R>
    <R>Data2</R>
    <R>Data3</R>
    <R>Data4</R>
    <R>Data5</R>
</Rows>

the wanted splitting is produced:

<Rows>
   <RGroup>
      <R>Data1</R>
      <R>Data2</R>
      <R>Data3</R>
   </RGroup>
   <RGroup>
      <R>Data4</R>
      <R>Data5</R>
   </RGroup>
</Rows>
野味少女 2024-11-11 19:10:41

此样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:redirect="http://xml.apache.org/xalan/redirect"
 extension-element-prefixes="redirect">
    <xsl:strip-space elements="*"/>
    <xsl:param name="pLimit" select="3"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:param name="pGroup"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pGroup" select="$pGroup"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/">
        <xsl:for-each select="//R[position() = 1 or position() = $pLimit + 1]">
            <redirect:write select="concat('output',position(),'.xml')">
                <xsl:apply-templates select="/node()">
                    <xsl:with-param name="pGroup" select="position()-1"/>
                </xsl:apply-templates>
            </redirect:write>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="R">
        <xsl:param name="pGroup"/>
        <xsl:if test="position() > $pLimit = $pGroup">
            <xsl:call-template name="identity"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

output1.xml:

<ExportData>
    <TransportHeader>
        <Timestamp>2011-01-16 06:00:33</Timestamp>
        <From>
            <Name>DynamicExport</Name>
            <Version>1.</Version>
        </From>
        <MessageId>d7b5c5b69a83</MessageId>
    </TransportHeader>
    <ExportConfig>
        <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
        <DecimalSymbol>.</DecimalSymbol>
    </ExportConfig>
    <DataSet>
        <Tables>
            <Table>
                <RH>...</RH>
                <Rows>
                    <R>Data1</R>
                    <R>Data2</R>
                    <R>Data3</R>
                </Rows>
            </Table>
        </Tables>
    </DataSet>
</ExportData>

output2.xml:

<ExportData>
    <TransportHeader>
        <Timestamp>2011-01-16 06:00:33</Timestamp>
        <From>
            <Name>DynamicExport</Name>
            <Version>1.</Version>
        </From>
        <MessageId>d7b5c5b69a83</MessageId>
    </TransportHeader>
    <ExportConfig>
        <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
        <DecimalSymbol>.</DecimalSymbol>
    </ExportConfig>
    <DataSet>
        <Tables>
            <Table>
                <RH>...</RH>
                <Rows>
                    <R>Data4</R>
                    <R>Data5</R>
                </Rows>
            </Table>
        </Tables>
    </DataSet>
</ExportData>

注意:这是针对非嵌套表的简单解决方案。 extension-element-prefixes 属性的使用。

This stylesheet:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:redirect="http://xml.apache.org/xalan/redirect"
 extension-element-prefixes="redirect">
    <xsl:strip-space elements="*"/>
    <xsl:param name="pLimit" select="3"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:param name="pGroup"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pGroup" select="$pGroup"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/">
        <xsl:for-each select="//R[position() = 1 or position() = $pLimit + 1]">
            <redirect:write select="concat('output',position(),'.xml')">
                <xsl:apply-templates select="/node()">
                    <xsl:with-param name="pGroup" select="position()-1"/>
                </xsl:apply-templates>
            </redirect:write>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="R">
        <xsl:param name="pGroup"/>
        <xsl:if test="position() > $pLimit = $pGroup">
            <xsl:call-template name="identity"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

output1.xml:

<ExportData>
    <TransportHeader>
        <Timestamp>2011-01-16 06:00:33</Timestamp>
        <From>
            <Name>DynamicExport</Name>
            <Version>1.</Version>
        </From>
        <MessageId>d7b5c5b69a83</MessageId>
    </TransportHeader>
    <ExportConfig>
        <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
        <DecimalSymbol>.</DecimalSymbol>
    </ExportConfig>
    <DataSet>
        <Tables>
            <Table>
                <RH>...</RH>
                <Rows>
                    <R>Data1</R>
                    <R>Data2</R>
                    <R>Data3</R>
                </Rows>
            </Table>
        </Tables>
    </DataSet>
</ExportData>

output2.xml:

<ExportData>
    <TransportHeader>
        <Timestamp>2011-01-16 06:00:33</Timestamp>
        <From>
            <Name>DynamicExport</Name>
            <Version>1.</Version>
        </From>
        <MessageId>d7b5c5b69a83</MessageId>
    </TransportHeader>
    <ExportConfig>
        <DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
        <DecimalSymbol>.</DecimalSymbol>
    </ExportConfig>
    <DataSet>
        <Tables>
            <Table>
                <RH>...</RH>
                <Rows>
                    <R>Data4</R>
                    <R>Data5</R>
                </Rows>
            </Table>
        </Tables>
    </DataSet>
</ExportData>

Note: This is a simple solution for not nested tables. The use of extension-element-prefixes attribute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文