首页 > 解决方案 > XSLT:使用输入 XML 中的唯一且已排序的日期创建新的 XML 节点

问题描述

我已经为此搜索了其他各种帖子,但到目前为止还没有能够使其正常工作。我需要在生成的 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>

任何帮助表示赞赏谢谢!

标签: xmlxsltxpath

解决方案


写一个模板

  <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>

通过恒等转换处理其余部分(即声明<xsl:mode on-no-match="shallow-copy"/>或说明 XSLT 2 的恒等转换模板:

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

)。


推荐阅读