【问题标题】:Grouping XML records with field name atttribute with XSL使用 XSL 对具有字段名称属性的 XML 记录进行分组
【发布时间】:2018-03-26 22:15:18
【问题描述】:

我正在尝试从此 XML 中选择值并生成分组的 XML 输出。 这是 XML 文件:我正在尝试使用 name 属性来获取各个字段值:select="field[@name='EmployeeEmployeeID']" ** 已编辑以添加分数字段 **

<?xml version="1.0" encoding="UTF-8"?>
<ExportXML xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <record>
    <field name="EmployeeEmployeeID">1234</field>
    <field name="EmployeeFirstName">John</field>
    <field name="EmployeeInitial">A</field>
    <field name="EmployeeLastName">Doe</field>
    <field name="EmployeeTitle">Title</field>
    <field name="ReviewRequest">2017 Review</field>
    <field name="Goal">Goal Title1A</field>
    <field name="Score">3</field>
  </record>
  <record>
    <field name="EmployeeEmployeeID">1234</field>
    <field name="EmployeeFirstName">John</field>
    <field name="EmployeeInitial">A</field>
    <field name="EmployeeLastName">Doe</field>
    <field name="EmployeeTitle">Title</field>
    <field name="ReviewRequest">2017 Review</field>
    <field name="Goal">Goal Title2A</field>
    <field name="Score">2</field>
  </record>
  <record>
    <field name="EmployeeEmployeeID">1234</field>
    <field name="EmployeeFirstName">John</field>
    <field name="EmployeeInitial">A</field>
    <field name="EmployeeLastName">Doe</field>
    <field name="EmployeeTitle">Title</field>
    <field name="ReviewRequest">2018 Review</field>
    <field name="Goal">Goal Title1B</field>
    <field name="Score">2</field>
  </record>
  <record>
    <field name="EmployeeEmployeeID">1234</field>
    <field name="EmployeeFirstName">John</field>
    <field name="EmployeeInitial">A</field>
    <field name="EmployeeLastName">Doe</field>
    <field name="EmployeeTitle">Title</field>
    <field name="ReviewRequest">2018 Review</field>
    <field name="Goal">Goal Title2B</field>
    <field name="Score">3</field>
  </record>
</ExportXML>

我正在尝试获取此输出: ** 已编辑以添加分数字段和部分 **

<?xml version="1.0" encoding="UTF-8"?>
<Reviews>
   <ReviewRequest>
     <EEID>1234</EEID>
     <EEFirstName>John</EEFirstName>
     <EEInitial>A</EEInitial>
     <EELastName>Doe</EELastName>
     <EETitle>Title</EETitle>
     <ReviewRequest>2017 Review</ReviewRequest>
     <Goals>
       <Goal>
         <Goal>Goal Title1A</Goal>
         <Score>3</Score>
       </Goal>
       <Goal>
         <Goal>Goal Title1A</Goal>
         <Score>2</Score>
       </Goal>
     </Goals>
  </ReviewRequest>
  <ReviewRequest>
     <EEID>1234</EEID>
     <EEFirstName>John</EEFirstName>
     <EEInitial>A</EEInitial>
     <EELastName>Doe</EELastName>
     <EETitle>Title</EETitle>
     <ReviewRequest>2018 Review</ReviewRequest>
     <Goals>
       <Goal>
         <Goal>Goal Title1B</Goal>
         <Score>2</Score>
       </Goal>
       <Goal>
         <Goal>Goal Title1B</Goal>
         <Score>3</Score>
       </Goal>
     </Goals>
  </ReviewRequest>
</Reviews>

我已尝试使用以下 XSL,但我似乎没有使用正确的选择器或正确分组。任何帮助将不胜感激。

<?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" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:fct="http://www.taleo.com/xsl_functions" xmlns:e="http://www.taleo.com/ws/tee800/2009/01" xmlns:itk="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:so="http://www.taleo.com/ws/so750/2006/12" exclude-result-prefixes="#all">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
    <xsl:template match="/ExportXML">
        <xsl:for-each-group select="./record" group-by="field[@name='ReviewRequest']">
            <xsl:variable name="EEID" select="field[@name='EmployeeEmployeeID']"/>
            <xsl:variable name="EEFirstName" select="field[@name='EmployeeFirstName']"/>
            <xsl:variable name="EEInitial" select="field[@name='EmployeeInitial']"/>
            <xsl:variable name="EELastName" select="field[@name='EmployeeLastName']"/>
            <xsl:variable name="EETitle" select="field[@name='EmployeeTitle']"/>
            <xsl:variable name="ReviewRequest" select="field[@name='ReviewRequest']"/>

            <ReviewRequest>
                <xsl:element name="EEID">
                    <xsl:value-of select="EEID"/>
                </xsl:element>
                <xsl:element name="EEFirstName">
                    <xsl:value-of select="EEFirstName"/>
                </xsl:element>
                <xsl:element name="EEInitial">
                    <xsl:value-of select="EEInitial"/>
                </xsl:element>
                <xsl:element name="EELastName">
                    <xsl:value-of select="EELastName"/>
                </xsl:element>
                <xsl:element name="EETitle">
                    <xsl:value-of select="EETitle"/>
                </xsl:element>
                <xsl:element name="ReviewRequest">
                    <xsl:value-of select="ReviewRequest"/>
                </xsl:element>
                <xsl:element name="Goal">
                    <xsl:for-each-group select="" group-by="field[@name='ReviewRequest']">
                        <xsl:element name="Goals">
                            <xsl:element name="Name">
                                <xsl:variable name="Goal" select="field[@name='Goal']"/>
                                <xsl:value-of select="Goal"/>
                            </xsl:element>
                        </xsl:element>
                        <xsl:value-of select="Goals"/>
                    </xsl:for-each-group>
                </xsl:element>
            </ReviewRequest>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

当前的xsl只是输出没有标签,没有分组的值...

    1234
    John
    A
    Doe
    Title
    2017 Review
    Goal Title1A


    1234
    John
    A
    Doe
    Title
    2017 Review
    Goal Title2A


    1234
    John
    A
    Doe
    Title
    2018 Review
    Goal Title1B


    1234
    John
    A
    Doe
    Title
    2018 Review
    Goal Title2B

我从下面的建议开始,最后得到以下建议:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/ExportXML">
    <Reviews>    
      <xsl:for-each-group select="record" 
        group-by="string-join((field[@name=('EmployeeEmployeeID','ReviewRequest')]),
        '|')">
        <ReviewRequest>
          <EEID>
            <xsl:value-of select="current-group()[1]/field[@name='EmployeeEmployeeID']"/>
          </EEID>
          <EEFirstName>
            <xsl:value-of select="current-group()[1]/field[@name='EmployeeFirstName']"/>
          </EEFirstName>
          <EEInitial>
            <xsl:value-of select="current-group()[1]/field[@name='EmployeeInitial']"/>
          </EEInitial>
          <EELastName>
            <xsl:value-of select="current-group()[1]/field[@name='EmployeeLastName']"/>
          </EELastName>
          <EETitle>
            <xsl:value-of select="current-group()[1]/field[@name='EmployeeTitle']"/>
          </EETitle>
          <ReviewRequest>
            <xsl:value-of select="current-group()[1]/field[@name='ReviewRequest']"/>
          </ReviewRequest>
            <Goals>
                <xsl:for-each select="current-group()/field[@name='Goal']">
                    <Goal>
                        <Goal><xsl:value-of select="."/></Goal>
                        <Score><xsl:value-of select="../field[@name='Score']"/></Score>
                    </Goal>
                </xsl:for-each>
            </Goals>
        </ReviewRequest>
      </xsl:for-each-group>      
    </Reviews>    
  </xsl:template>

</xsl:stylesheet>

产生这个结果:

<?xml version="1.0" encoding="UTF-8"?>
<Reviews>
   <ReviewRequest>
      <EEID>1234</EEID>
      <EEFirstName>John</EEFirstName>
      <EEInitial>A</EEInitial>
      <EELastName>Doe</EELastName>
      <EETitle>Title</EETitle>
      <ReviewRequest>2017 Review</ReviewRequest>
      <Goals>
         <Goal>
            <Goal>Goal Title1A</Goal>
            <Score>3</Score>
         </Goal>
         <Goal>
            <Goal>Goal Title2A</Goal>
            <Score>2</Score>
         </Goal>
      </Goals>
   </ReviewRequest>
   <ReviewRequest>
      <EEID>1234</EEID>
      <EEFirstName>John</EEFirstName>
      <EEInitial>A</EEInitial>
      <EELastName>Doe</EELastName>
      <EETitle>Title</EETitle>
      <ReviewRequest>2018 Review</ReviewRequest>
      <Goals>
         <Goal>
            <Goal>Goal Title1B</Goal>
            <Score>2</Score>
         </Goal>
         <Goal>
            <Goal>Goal Title2B</Goal>
            <Score>3</Score>
         </Goal>
      </Goals>
   </ReviewRequest>
</Reviews>

http://xsltfiddle.liberty-development.net/bFukv8v/2

【问题讨论】:

    标签: xml xslt xslt-2.0


    【解决方案1】:

    您得到的输出是built-in template rules 的结果。这是因为您没有考虑默认命名空间 (http://www.taleo.com/ws/integration/toolkit/2005/07)。所以/ExportXML 什么都不匹配。

    除了考虑默认命名空间之外,还可以考虑使用复合 group-by 而不是两个嵌套的 for-each-group。

    分组键是“EmployeeEmployeeID”字段和“ReviewRequest”字段的组合。

    假设每个组除了目标之外的所有内容都相同,您可以执行以下操作:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07">
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="/ExportXML">
        <Reviews>
          <xsl:for-each-group select="record" 
            group-by="string-join((field[@name=('EmployeeEmployeeID','ReviewRequest')]),
            '|')">
            <ReviewRequest>
              <EEID>
                <xsl:value-of select="current-group()[1]/field[@name='EmployeeEmployeeID']"/>
              </EEID>
              <EEFirstName>
                <xsl:value-of select="current-group()[1]/field[@name='EmployeeFirstName']"/>
              </EEFirstName>
              <EEInitial>
                <xsl:value-of select="current-group()[1]/field[@name='EmployeeInitial']"/>
              </EEInitial>
              <EELastName>
                <xsl:value-of select="current-group()[1]/field[@name='EmployeeLastName']"/>
              </EELastName>
              <EETitle>
                <xsl:value-of select="current-group()[1]/field[@name='EmployeeTitle']"/>
              </EETitle>
              <ReviewRequest>
                <xsl:value-of select="current-group()[1]/field[@name='ReviewRequest']"/>
              </ReviewRequest>
              <xsl:for-each select="current-group()/field[@name='Goal']">
                <Goal><xsl:value-of select="."/></Goal>
              </xsl:for-each>
            </ReviewRequest>
          </xsl:for-each-group>      
        </Reviews>
      </xsl:template>
    
    </xsl:stylesheet>
    

    小提琴:http://xsltfiddle.liberty-development.net/948Fn5t

    您还可以稍微简化元素创建(这也说明了您添加的Score 要求)...

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07">
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="/ExportXML">
        <Reviews>
          <xsl:for-each-group select="record" 
            group-by="string-join((field[@name=('EmployeeEmployeeID','ReviewRequest')]),
            '|')">
            <ReviewRequest>
              <xsl:apply-templates 
                select="current-group()[1]/field[not(@name=('Goal','Score'))]"/>
              <Goals>
                <xsl:apply-templates select="current-group()/field[@name='Goal']"/>
              </Goals>
            </ReviewRequest>
          </xsl:for-each-group>      
        </Reviews>
      </xsl:template>
    
      <xsl:template match="field[@name='Goal']">
        <Goal>
          <Goal><xsl:value-of select="."/></Goal>
          <xsl:apply-templates select="../field[@name='Score']"/>
        </Goal>
      </xsl:template>
    
      <xsl:template match="field">
        <xsl:element name="{replace(@name,'^(Employee)+(.*)','EE$2')}">
          <xsl:apply-templates/>
        </xsl:element>
      </xsl:template>
    
    </xsl:stylesheet>
    

    更新小提琴:http://xsltfiddle.liberty-development.net/948Fn5t/2

    【讨论】:

    • 谢谢!这已经比我以前的效果好得多了!有几件事。实际上,每个目标都会有一些额外的字段,所以我需要创建一个目标部分,每个目标都有名称和分数。
    • 这是我目前的进度
    • @BenEsteban - 我更新了我的第二个样式表和小提琴来处理您的Score 要求。
    • @BenEsteban - 现在我仔细研究了您的问题,我发现您得到的输出与我相同,并且似乎是您想要的输出。您真的还有其他问题吗?
    • 此时输出看起来很棒!感谢您的帮助!
    猜你喜欢
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2015-03-20
    • 2018-04-22
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    相关资源
    最近更新 更多