Xslt 循环并将子节点拆分为多个子节点

Xslt 循环并将子节点拆分为多个子节点,xslt,xslt-2.0,Xslt,Xslt 2.0,这是我需要使用XSLT2.0转换的输入XML <?xml version="1.0" encoding="UTF-8"?> <Workers> <Worker> <id>1234</id> <loc>New York</loc> <Days>1</Days> <StartDate>2019-01-26<

这是我需要使用XSLT2.0转换的输入XML

<?xml version="1.0" encoding="UTF-8"?>
<Workers>
    <Worker>
        <id>1234</id>
        <loc>New York</loc>
        <Days>1</Days>
        <StartDate>2019-01-26</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <Batch>A</Batch>
        <Days>3</Days>
        <Units>2</Units>
        <StartDate>2019-02-01</StartDate>
    </Worker>
</Workers>
电流输出

<?xml version="1.0" encoding="UTF-8"?>
<Workers>
    <Worker>
        <id>1234</id>
        <loc>New York</loc>
        <Days>1</Days>
        <StartDate>2019-01-26</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>1</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-02</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>2</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-03</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>3</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-04</StartDate>
    </Worker>
</Workers>
预期产量

<?xml version="1.0" encoding="UTF-8"?>
<Workers>
    <Worker>
        <id>1234</id>
        <loc>New York</loc>
        <Days>1</Days>
        <StartDate>2019-01-26</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>1</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-01</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>2</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-02/StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>3</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-03</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>1</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-01</StartDate>
    </Worker>
    <Worker>
        <id>2345</id>
        <loc>Boston</loc>
        <RecordNumber>2</RecordNumber>
        <WorkerDays>1</WorkerDays>
        <StartDate>2019-02-02/StartDate>
    </Worker>
</Workers>
我的要求是

a。如果子节点中不存在元素,则应复制XML中显示的子节点。在上面的XML中,第一个worker子节点应该按照它在XML中的显示进行复制,因为它没有元素

b。若元素存在于子节点中,则需要根据以下两个条件将该子节点拆分为多个子节点

一,。子节点的数量需要创建的次数与元素的值相同。在本例中,值为3,因此需要创建3个子节点,并且这些子节点中的每一个子节点都应该增加1,并创建一个新元素,该元素应该包含该循环的值

二,。再次需要根据元素的值拆分子节点。在上面的XML中,是2,所以需要创建两倍的子节点,并且每次创建和创建一个应该保存该循环值的新元素时,子节点需要增加一倍

当前XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:functx="http://www.functx.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Workers/Worker[exists(Batch)]">
        <xsl:variable name="start" select="1"/>
        <xsl:variable name="counter" select="Days"/>
        <xsl:variable name="Records" select="."/>
        <xsl:for-each select="$start to $counter">
            <xsl:apply-templates select="$Records" mode="replicate">
                <xsl:with-param name="data" select="."/>
            </xsl:apply-templates>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="Workers/Worker" mode="replicate">
        <xsl:param name="data"/>
        <Worker>
            <id>
                <xsl:value-of select="id"/>
            </id>
            <loc>
                <xsl:value-of select="loc"/>
            </loc>
            <RecordNumber>
                <xsl:value-of select="$data"/>
            </RecordNumber>
            <WorkerDays>1</WorkerDays>
            <StartDate>
                <xsl:value-of select="xs:date(StartDate) + xs:dayTimeDuration('P1D') * $data"/>
            </StartDate>
        </Worker>
    </xsl:template>
</xsl:stylesheet>
问题:

的值错误-似乎缺少实际值

XSLT根本没有基于拆分子节点

子节点应该在预期输出中出现6次,而我现在只看到4次

有人能帮我解决这个问题吗


感谢您的预期输出,我发现您需要一个序列中的两个循环:

第一次执行的天数, 第二个执行单元的次数, 从输入日期开始的连续日期的两个

还请注意,在for-each循环中,上下文项会发生更改,因此 对于两种情况,对于每个循环,上下文项是当前的循环数 执行,采取形式选择属性

这就是为什么在每个循环中,当调用工作模板时, dayNo参数以点形式给出,currElem为 只是调用了Worker[Batch]模板的元素

就输出StartDate而言,dayTimeDuration必须是 添加$dayNo-1次

其他有用的补充/更改包括:

一开始,情况会好一些 输出的缩进。 -将源元素复制到输出的较短形式。 还值得注意的是,它运行更快,消耗更多 内存更少。 我删除了一些只使用了一次的变量。 您使用了一个名为data的变量。我觉得这个名字太笼统了, 所以我把它改为currElem当前元素。 因此,整个脚本可以如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
  <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="Worker[Batch]">
    <xsl:variable name="currElem" select="."/>
    <xsl:for-each select="1 to Days">
      <xsl:apply-templates select="$currElem" mode="replicate">
        <xsl:with-param name="dayNo" select="."/>
      </xsl:apply-templates>
    </xsl:for-each>
    <xsl:for-each select="1 to Units">
      <xsl:apply-templates select="$currElem" mode="replicate">
        <xsl:with-param name="dayNo" select="."/>
      </xsl:apply-templates>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Worker" mode="replicate">
    <xsl:param name="dayNo"/>
    <Worker>
      <xsl:sequence select="id, loc"/>
      <RecordNumber><xsl:value-of select="$dayNo"/></RecordNumber>
      <WorkerDays>1</WorkerDays>
      <StartDate>
        <xsl:value-of select="xs:date(StartDate) + xs:dayTimeDuration('P1D') * ($dayNo - 1)"/>
      </StartDate>
    </Worker>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>
</xsl:stylesheet>
有关工作示例,请参见

如果需要,第一个版本正在下载中
比较一下。

谢谢你,瓦迪乌波。当我试图理解您的代码时,我发现它返回的输出有问题。的值为2,所以只需创建两次元素。现在它返回了3次。预期输出应该只有6个节点。这是每个外部循环的问题吗?您的输入XML包含2次执行外部循环的次数和3次执行连续日期的内部循环的次数。因此,我的脚本生成了预期的结果。另一方面,多次生成完全相同的内容有点奇怪,但我就是这样理解你的问题的。或者也许外环的结果应该在某些方面有所不同?很抱歉让您混淆了我的要求。让我举一个例子来说明我的要求。如果值为9且为2,则需要创建11次元素。。由于您所述的原因,现在创建了18次-外部循环执行的次数为。另一个例子。。如果单位为5,天数为10-15倍,则需要创建Worker元素。。同一内容需要多次生成的原因是下游系统的要求,因为它们需要逐个处理RecordNumber和StartDates。根据您最近评论中的解释,我更正了解决方案。现在应该没事了。