XSLT:在重新排列 XML 时面临多个父节点的问题

Posted

技术标签:

【中文标题】XSLT:在重新排列 XML 时面临多个父节点的问题【英文标题】:XSLT: Facing issue with multiple parent nodes in while re-arranging XML 【发布时间】:2021-10-31 03:57:33 【问题描述】:

我正在使用下面的 XSLT 根据有效日期重新排列/收集 XML 中的各种节点。

这是 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="/">
        <CompoundEmployee>
        <xsl:variable name="var_person" select="//person/*[not(name()='personal_information') and not(name()='phone_information') and not(name()='email_information') and not(name()='employment_information')]"></xsl:variable>
        <xsl:for-each select="//StartDate">
         <xsl:variable name="i" select="position()"/>
         <xsl:variable name="newDate" select="replace(//StartDate[$i],'-','')"/>
          <Record>
              <xsl:copy-of select="//StartDate[$i]"/>
              <xsl:copy-of select="$var_person"/>
              <xsl:copy-of select="//CompoundEmployee/person/personal_information[replace(start_date,'-','') &lt;= $newDate and $newDate &lt;= replace(end_date,'-','')]"/>
          <xsl:copy-of select="//CompoundEmployee/person/employment_information/job_information[replace(start_date,'-','') &lt;= $newDate and $newDate &lt;= replace(end_date,'-','')]"/>
         <xsl:copy-of select="//CompoundEmployee/person/employment_information[(replace(start_date,'-','') &lt;= $newDate and ($newDate &lt;= replace(end_date,'-','') or not(end_date)))]"/>
          </Record>
        </xsl:for-each>
        </CompoundEmployee>
    </xsl:template>
</xsl:stylesheet>

只要只有一个 CompoundEmployee 节点,它就可以正常工作。但我可以在根查询CompoundEmployeeResponse 中获得多个 CompoundEmployee 节点。这是输入 XML:

    <?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse>
<CompoundEmployee>
    <id>176</id>
    <person>
        <action>NO CHANGE</action>
        <created_by>CONV_ADMIN</created_by>
        <logon_user_id>1234567</logon_user_id>
        <logon_user_is_active>true</logon_user_is_active>
        <person_id>176</person_id>
        <person_id_external>1234567</person_id_external>
        <personal_information>
            <end_date>9999-12-31</end_date>
            <first_name>yutaka</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2021-06-03</start_date>
        </personal_information>
        <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-06</start_date>
        </personal_information>
        <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
    </person>
    <StartDates>
    <StartDate>2021-06-03</StartDate>
    <StartDate>2017-12-06</StartDate>
    <StartDate>2017-12-06</StartDate>
    <StartDate>2019-03-02</StartDate>
    </StartDates>
</CompoundEmployee>
<CompoundEmployee>
    <id>176</id>
    <person>
        <action>NO CHANGE</action>
        <created_by>CONV_ADMIN</created_by>
        <logon_user_id>1234567</logon_user_id>
        <logon_user_is_active>true</logon_user_is_active>
        <person_id>176</person_id>
        <person_id_external>1234567</person_id_external>
        <personal_information>
            <end_date>9999-12-31</end_date>
            <first_name>yutaka</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2021-06-03</start_date>
        </personal_information>
        <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-06</start_date>
        </personal_information>
        <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
    </person>
    <StartDates>
    <StartDate>2021-06-01</StartDate>
    <StartDate>2017-12-05</StartDate>
    <StartDate>2017-12-07</StartDate>
    <StartDate>2019-03-08</StartDate>
    </StartDates>
</CompoundEmployee>
</queryCompoundEmployeeResponse>

错误: 在第 12 行执行 XSLT 时出错:不允许将多个项目的序列作为 fn:replace() ("2021-06-03", "2021-06-03") 的第一个参数

预期的 XML

<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse>
<CompoundEmployee>
   <Record>
      <StartDate>2021-06-03</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>9999-12-31</end_date>
            <first_name>yutaka</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2021-06-03</start_date>
        </personal_information>
      <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
   </Record>
   <Record>
      <StartDate>2017-12-06</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-06</start_date>
        </personal_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
   </Record>
   <Record>
      <StartDate>2017-12-06</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-06</start_date>
        </personal_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
   </Record>
   <Record>
      <StartDate>2019-03-02</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-06</start_date>
        </personal_information>
      <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-06</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-02</start_date>
            </job_information>
        </employment_information>
   </Record>
</CompoundEmployee>
<CompoundEmployee>
   <Record>
      <StartDate>2021-06-01</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>9999-12-31</end_date>
            <first_name>yutaka</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2021-06-01</start_date>
        </personal_information>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-05</start_date>
        </personal_information>
      <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-08</start_date>
            </job_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-07</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-08</start_date>
            </job_information>
        </employment_information>
   </Record>
   <Record>
      <StartDate>2017-12-05</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-05</start_date>
        </personal_information>
   </Record>
   <Record>
      <StartDate>2017-12-07</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-05</start_date>
        </personal_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-07</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-08</start_date>
            </job_information>
        </employment_information>
   </Record>
   <Record>
      <StartDate>2019-03-08</StartDate>
      <action>NO CHANGE</action>
      <created_by>CONV_ADMIN</created_by>
      <logon_user_id>1234567</logon_user_id>
      <logon_user_is_active>true</logon_user_is_active>
      <person_id>176</person_id>
      <person_id_external>1234567</person_id_external>
      <personal_information>
            <end_date>2021-06-02</end_date>
            <first_name>wataru</first_name>
            <first_name_previous>Robbin</first_name_previous>
            <first_name_alt1>Robbin</first_name_alt1>
            <start_date>2017-12-05</start_date>
        </personal_information>
      <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-08</start_date>
            </job_information>
      <employment_information>
            <employment_id>136</employment_id>
            <start_date>2017-12-07</start_date>
            <user_id>10005005</user_id>
            <job_information>
                <action>NO CHANGE</action>
                <end_date>9999-12-31</end_date>
                <entry_into_group>2017-12-06</entry_into_group>
                <event>5</event>
                <event_reason>DATACONV</event_reason>
                <excl_executive_sector>false</excl_executive_sector>
                <fte>1.0</fte>
                <hazard>false</hazard>
                <job_code>1000039</job_code>
                <location>10000069</location>
                <manager_employment_id>265</manager_employment_id>
                <manager_id>10005069</manager_id>
                <manager_person_id>305</manager_person_id>
                <manager_person_id_external>10005069</manager_person_id_external>
                <start_date>2019-03-08</start_date>
            </job_information>
        </employment_information>
   </Record>
</CompoundEmployee>

即使有多个 CompoundEmployee 节点,我也需要让它工作。另外,请让我知道是否有更好的方法来做到这一点。我通过浏览一些博客创建了这个。谢谢!

【问题讨论】:

究竟什么是“不”工作?你有错误吗?如果有,具体是哪一个?你得到错误的结果吗?然后显示想要的结果和当前的结果。 用无效的 XML 更新了问题。还添加了错误。如果 XML 只有一个 CompoundEmployee,XSLT 就可以工作,在这种情况下,它会生成一个 XML,其中有 1 个 CompoundEmployee 节点,有 4 个“记录”。预期的 XML 应该有 2 个 CompoundEmployee 节点,每个节点有 4 条记录。 请编辑您的问题并添加预期的输出。请注意,如果您为输入中的每个 CompoundEmployee 创建一个 CompoundEmployee 节点,则需要添加一个根元素 - 否则您的结果将不是一个格式良好的 XML 文档。 正如我所说,您发布的是一个 XML 片段。确定这是您想要的吗? 添加了预期的 XML。好的,可以添加一个根元素,我可以稍后处理。谢谢! 【参考方案1】:

通常我会建议使用模板匹配和相对于匹配元素的路径,例如

<xsl:template match="CompoundEmployee">
  <xsl:copy>

    <xsl:for-each select=".//StartDate">

或者更好的更多模板,例如

<xsl:template match="CompoundEmployee">
  <xsl:copy>

    <xsl:apply-templates select=".//StartDate"/>

 </xsl:copy>
</xsl:template>

<xsl:template match="StartDate">
  <Record>
     <xsl:copy-of select="."/> <!-- copies the match StartDate element -->
     ...
  </Record>
</xsl:template>

【讨论】:

【参考方案2】:

恕我直言,您将可能相对简单的事情复杂化了。

试试这个作为你的起点:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/queryCompoundEmployeeResponse">
    <root>
        <xsl:for-each select="CompoundEmployee">
            <xsl:copy>
                <xsl:variable name="person" select="person" />
                <xsl:for-each select="StartDates/StartDate">
                    <Record>
                        <xsl:copy-of select="."/>
                        <xsl:copy-of select="$person/* except $person/(personal_information | phone_information | email_information | employment_information)"/>
                        
                        <!-- copy relevant personal information -->
                        <xsl:copy-of select="$person/personal_information[start_date le current() and current() le end_date]"/>
                        
                        <!-- do the same for the other types of information -->
                        
                    </Record>
                </xsl:for-each>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>
    
</xsl:stylesheet>   

【讨论】:

这正是我所需要的。不知道 current(),比使用索引方便得多。非常感谢..!

以上是关于XSLT:在重新排列 XML 时面临多个父节点的问题的主要内容,如果未能解决你的问题,请参考以下文章

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

使用 xslt 将 xml 复杂节点元素拆分为多个节点

在封闭元素下排列节点 - XSLT

基本 XML/XSLT - 存在多个同名元素时的值

如何使用 xslt 将父节点命名空间复制到子元素?

在 XSLT 中对每个父节点下的子节点进行分组