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

时间:2019-02-19 21:59:30

标签: xslt xslt-2.0

这是我需要使用XSLT 2.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。)如果子节点中不存在元素<Batch>,则应按照XML中出现的方式复制该子节点。在上面的XML中,应该复制第一个辅助子节点,因为它没有包含<Batch>元素。

b。)如果子节点中存在元素<Batch>,则需要根据以下两个条件将该子节点拆分为多个子节点

1。)子节点的创建次数需要与元素<Days>的值一样多。在这种情况下,<Days>的值为3,因此需要创建3个子节点,并且每个子节点应将<StartDate>递增1并创建一个新元素<RecordNumber>应该包含该循环的值。

2。)再次需要根据元素<Units>的值拆分子节点。在上述XML中,<Units>为2,因此需要创建两次子节点,并且每次创建并创建一个新元素<StartDate>时,<RecordNumber>都需要增加一个。保持那个循环的值

当前的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>

问题:

  1. <StartDate>的值有误-似乎缺少实际的<StartDate>

  2. XSLT根本不拆分子节点。

  3. <Worker>子节点应该在预期输出中出现6次,而现在我只有4次。

有人可以帮我解决此问题吗?

谢谢

1 个答案:

答案 0 :(得分:1)

从您的预期输出中,我看到您需要按顺序依次2个循环:

  • 第一次执行file(READ "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" CONFIG_H_IN) string(CONFIGURE "${CONFIG_H_IN}" CONFIG_H_TMP) file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config.h" CONTENT "${CONFIG_H_TMP}") 次,
  • 第二次-执行Days次,

都是连续的日期,从输入日期开始。

请注意,在Units循环中,上下文项已更改,因此在 在两个for-each循环的情况下,上下文项是的当前编号 执行,格式为for-each

这是在每个循环中调用select模板时的原因, Worker参数以的形式给出,而 currElem 是 只是为其调用了dayNo模板的元素。

就输出Worker[Batch]而言,StartDate必须 被添加dayTimeDuration次。

另一个有用的添加/更改是:

  • $dayNo - 1开头,导致“更好” 输出缩进。
  • <xsl:strip-space elements="*"/>-较短的形式,用于将源元素复制到输出。 还需要注意的是,它运行更快,消耗很多 更少的内存。
  • 我删除了仅使用1次的一些变量。
  • 您使用了一个名为<xsl:sequence .../>的变量。恕我直言,这个名字是“太笼统”, 所以我将其更改为data(当前元素)。

因此整个脚本如下所示:

currElem

有关工作示例,请参见http://xsltransform.net/asnmyP/1

第一个版本位于http://xsltransform.net/asnmyP下(如果需要的话) 进行比较)。