XSLT:使用输入 XML 中的唯一且已排序的日期创建新的 XML 节点

Posted

技术标签:

【中文标题】XSLT:使用输入 XML 中的唯一且已排序的日期创建新的 XML 节点【英文标题】:XSLT: Create new XML node with unique and sorted dates from input XML 【发布时间】:2021-10-30 20:53:45 【问题描述】:

我已经为此搜索了各种其他帖子,但到目前为止还没有得到这个工作。 我需要在生成的 XML 中添加一个新节点,该节点应该包含输入 XML 中的所有“start_date”节点。结果节点应具有按升序排序的唯一日期。 这是我的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <record>
        <id>378</id>
        <A>
            <Field1>378</Field1>
            <AX>
                <Field1>x</Field1>
                <Field2>xx</Field2>
            </AX>
            <AY>
                <Field1>yy</Field1>
            </AY>
            <B>
                <end_date>9999-12-31</end_date>
                <start_date>2019-03-27</start_date>
            </B>
            <B>
                <end_date>9999-12-31</end_date>
                <start_date>2019-03-27</start_date>
            </B>
            <C>
                <start_date>2012-02-01</start_date>
                <user_id>10005557</user_id>
                <D>
                    <end_date>9999-12-31</end_date>
                    <start_date>2021-06-30</start_date>
                </D>
            </C>
        </A>
    </record>
    <record>
        <id>379</id>
        <A>
            <Field1>300</Field1>
            <AX>
                <Field1>x</Field1>
                <Field2>xx</Field2>
            </AX>
            <AY>
                <Field1>yy</Field1>
            </AY>
            <B>
                <end_date>9999-12-31</end_date>
                <start_date>2019-03-27</start_date>
            </B>
            <C>
                <start_date>2012-02-01</start_date>
                <user_id>10005557</user_id>
                <D>
                    <end_date>9999-12-31</end_date>
                    <start_date>2021-06-30</start_date>
                </D>
            </C>
        </A>
    </record>
</root>

这是我的 XSLT:

<?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="xs">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />
      
   
    <xsl:template match="/">
        <root>
            <xsl:for-each select="//record">
              
             <record>
                <xsl:copy-of select="./*"/>
                <xsl:variable name="i" select="position()"/>
                  <StartDates>
                    <xsl:copy-of select="//child::record[$i]/descendant::start_date"/>
                  </StartDates>
             </record>
            </xsl:for-each>
      </root>
    </xsl:template>
    
    <xsl:template match="StartDates">
        <xsl:variable name="nDate" select="replace(//start_date,'-','')"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
       <xsl:apply-templates select="$nDate">
          <xsl:sort select="$nDate"/>
       </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

第一个模板是收集所有日期。在第二个模板中,我试图对这些日期进行排序。谁能帮我排序和选择独特的日期。

这是预期的输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <record>
      <id>378</id>
      <A>
                  <Field1>378</Field1>
                  <AX>
                        <Field1>x</Field1>
                        <Field2>xx</Field2>
                  </AX>
                  <AY>
                        <Field1>yy</Field1>
                  </AY>
                  <B>
                        <end_date>9999-12-31</end_date>
                        <start_date>2019-03-27</start_date>
                  </B>
                  <B>
                        <end_date>9999-12-31</end_date>
                        <start_date>2019-03-27</start_date>
                  </B>
                  <C>
                        <start_date>2012-02-01</start_date>
                        <user_id>10005557</user_id>
                        <D>
                              <end_date>9999-12-31</end_date>
                              <start_date>2021-06-30</start_date>
                        </D>
                  </C>
            </A>
      <StartDates>
         <start_date>2012-02-01</start_date>
         <start_date>2019-03-27</start_date>
         <start_date>2021-06-30</start_date>
      </StartDates>
   </record>
   <record>
      <id>379</id>
      <A>
                  <Field1>300</Field1>
                  <AX>
                        <Field1>x</Field1>
                        <Field2>xx</Field2>
                  </AX>
                  <AY>
                        <Field1>yy</Field1>
                  </AY>
                  <B>
                        <end_date>9999-12-31</end_date>
                        <start_date>2019-03-27</start_date>
                  </B>
                  <C>
                        <start_date>2012-02-01</start_date>
                        <user_id>10005557</user_id>
                        <D>
                              <end_date>9999-12-31</end_date>
                              <start_date>2021-06-30</start_date>
                        </D>
                  </C>
            </A>
      <StartDates>
         <start_date>2012-02-01</start_date>
         <start_date>2019-03-27</start_date>
         <start_date>2021-06-30</start_date>
      </StartDates>
   </record>
</root>

感谢任何帮助!

【问题讨论】:

【参考方案1】:

编写模板

  <xsl:template match="record">
    <xsl:copy>
      <xsl:apply-templates/>
      <StartDates>
        <xsl:for-each-group select=".//start_date" group-by=".">
          <xsl:sort select="."/>
          <xsl:copy-of select="."/>
        </xsl:for-each-group>
      </StartDates>
    </xsl:copy>
  </xsl:template>

通过恒等转换处理其余部分(即声明 &lt;xsl:mode on-no-match="shallow-copy"/&gt; 或拼出 XSLT 2 的恒等转换模板:

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

)。

【讨论】:

这就像一个魅力。非常感谢!您能否简要解释一下这是如何选择唯一日期的。当我尝试使用 for-each 时,它会将所有日期都放在一个上下文中。我是 XSLT 和学习新手。再次感谢! &lt;xsl:for-each-group select=".//start_date" group-by="."&gt;start_date 元素按其字符串值分组,内部的xsl:sort 进行排序,因为&lt;xsl:copy-of select="."/&gt;&lt;xsl:copy-of select="current-group()[1]"/&gt; 相同,即输出第一个每个组的项,仅输出唯一的start_date 元素。

以上是关于XSLT:使用输入 XML 中的唯一且已排序的日期创建新的 XML 节点的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 3.0 中的日期排序

使用 XSLT 从同一输入 XML 中提取的最新日期更新输入 XML

使用 xslt 按升序对 xsd 格式的 XML 进行排序

使用 XML 中的多列进行 XSLT 排序

使用 CDATA 元素对 xml 中的 uuid 进行排序的 xslt 模板

如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序