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 节点的主要内容,如果未能解决你的问题,请参考以下文章