XSLT分组平面XML

时间:2014-03-10 19:19:37

标签: xml xslt xml-parsing

我有一个来自数据库的平面XML文件。我需要使用XSL转换将数据分组为更分层的布局。我已经研究了很多,并提出Meunchian分组作为前进的方向,但无法让它工作。

我要来自:

<Report>
<Data>
    <Row>
        <Field name ="AssessmentID">1</Field>
        <Field name ="Company">Test Company</Field>
        <Field name ="Manager">Bob Smith</Field>
        <Field name ="IssueID">1-1</Field>
        <Field name ="IssueTitle">Security Problem</Field>
        <Field name ="IssueDescription">Some Description</Field>
    </Row>
    <Row>
        <Field name ="AssessmentID">1</Field>
        <Field name ="Company">Test Company</Field>
        <Field name ="Manager">Bob Smith</Field>
        <Field name ="IssueID">1-2</Field>
        <Field name ="IssueTitle">Other Problem</Field>
        <Field name ="IssueDescription">Some Other Description</Field>
    </Row>
</Data>
</Report>

对此:

<Assessments>
<Assessment>
    <AssessmentID>1</AssessmentID>
    <Company>Test Company</Company>
    <Manager>Bob Smith</Manager>
    <Issue>
        <IssueID>1-1</IssueID>
        <IssueTitle>Security Problem</IssueTitle>
        <IssueDescription>Some Description</IssueDescription>
    </Issue>
    <Issue>
        <IssueID>1-2</IssueID>
        <IssueTitle>Other Problem</IssueTitle>
        <IssueDescription>Some Other Description</IssueDescription>
    </Issue>
</Assessment>
</Assessments>

这是我到目前为止提出的代码:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
        <xsl:key name="keyAssessmentID" match="Row" use="Field[@name='AssessmentID']"/>
        <xsl:key name="keyIssueID" match="Row" use="Field[@name='IssueID']"/>
    <xsl:template match="/">
        <Assessments>
            <!-- Process each Assessment -->
        <xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">
                <!-- Select all the issues belonging to the assessment -->
                    <xsl:variable name ="lngAssessmentID"><xsl:value-of select="Field[@name='AssessmentID']" /></xsl:variable>
                    <xsl:variable name="lstIssue" select="//Row[Field[@name='IssueID']=$lngAssessmentID]" />

                    <!-- show details for Issues in Assessments -->
                    <xsl:call-template name="ShowIssuesInAssessment">
                        <xsl:with-param name="lstIssue" select="$lstIssue" />
                    </xsl:call-template>
        </xsl:for-each>             
        </Assessments>
    </xsl:template>

    <xsl:template name="ShowIssuesInAssessment">
        <xsl:param name="lstIssue" />

        <!-- Show the name of the Assessment currently being processed -->
        <AssessmentID>
            <xsl:value-of select="$lstIssue[1]/Field[@name='AssessmentID']" />
        </AssessmentID>

 <!-- Show IssueID for each Issue in the Assessment -->
 <xsl:for-each select="$lstIssue[generate-id(.) = generate-id(key('keyIssueID', Field[@Name='IssueID'])[1])]">
  <xsl:variable name="lngIssueID" select="Field[@Name='IssueID']" />
  <!-- Show details of each Issue -->
  <Issue>
    <IssueID>
        <xsl:value-of select="$lstIssue[Field[@Name='IssueID']=$lngIssueID]/Field[@Name='IssueID']" />
     </IssueID>
     <IssueTitle>
            <xsl:value-of select="$lstIssue[Field[@Name='IssueID']=$lngIssueID]/Field[@Name='IssueTitle']" />
   </IssueTitle>
   </Issue>
     </xsl:for-each>
     </xsl:template>
    </xsl:stylesheet>

我正在使用CodeProject上的这个示例:here

感谢大家的帮助!

2 个答案:

答案 0 :(得分:2)

通过使用Muenchian Grouping首次出现每个 AssessmentID

,您已经正确启动
<xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">

但要获得评估的所有“问题”,您应该实际使用密钥(其中 $ AssessmentId 是包含AssessmentId的变量)

<xsl:apply-templates select="key('keyAssessmentID', $AssessmentId)"/>

我在这里看不到需要使用 xsl:call-template ,或者将组中的元素作为参数传入。只需使用模板匹配,这是XSLT擅长的。然后在匹配的模板中,您可以输出问题详细信息

<xsl:template match="Row">
   <Issue>
      <xsl:apply-templates select="Field[@name='IssueID']"/>
      <xsl:apply-templates select="Field[@name='IssueTitle']"/>
      <xsl:apply-templates select="Field[@name='IssueDescription']"/>
   </Issue>
</xsl:template>

为了保存代码重复,您可以使用与这些变量字段匹配的单个模板

<xsl:template match="Row/*">
   <xsl:element name="{@name}">
      <xsl:value-of select="."/>
   </xsl:element>
</xsl:template>

(这使用“属性值模板”根据字段的 @name 属性值创建元素名称。)

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:key name="keyAssessmentID" match="Row" use="Field[@name='AssessmentID']"/>

   <xsl:template match="/*">
      <Assessments>
         <xsl:for-each select=".//Row[generate-id(.) = generate-id(key('keyAssessmentID', Field[@name='AssessmentID'])[1])]">
            <xsl:variable name="AssessmentId" select="Field[@name='AssessmentID']"/>
            <Assessment>
               <AssessmentID>
                  <xsl:value-of select="$AssessmentId"/>
               </AssessmentID>
               <xsl:apply-templates select="key('keyAssessmentID', $AssessmentId)"/>
            </Assessment>
         </xsl:for-each>
      </Assessments>
   </xsl:template>

   <xsl:template match="Row">
      <Issue>
         <xsl:apply-templates select="Field[@name='IssueID']"/>
         <xsl:apply-templates select="Field[@name='IssueTitle']"/>
         <xsl:apply-templates select="Field[@name='IssueDescription']"/>
      </Issue>
   </xsl:template>

   <xsl:template match="Row/*">
      <xsl:element name="{@name}">
         <xsl:value-of select="."/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

然后,阅读http://www.jenitennison.com/xslt/grouping/muenchian.html以更好地了解Muenchian分组。

答案 1 :(得分:0)

@Tim C的精彩回答,但我想我会加入我的角度略有不同。我认为关键是你似乎也在那里使用keyIssueID键,这根本不是真的需要,根据你建议的输出,你只需要一个AssessmentID的密钥

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:key name="keyAssessmentID" match="Row" use="./Field[@name='AssessmentID']"/>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <xsl:element name="Assessments">
      <xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyAssessmentID',Field[@name='AssessmentID']))]">
        <xsl:element name="Assesment">
          <xsl:variable name="AssessmentId" select="./Field[@name='AssessmentID']" />
          <xsl:element name="AssessmentId">
            <xsl:value-of select="$AssessmentId"/>
          </xsl:element>
          <xsl:element name="Company">
            <xsl:value-of select="./Field[@name='Company']"/>
          </xsl:element>
          <xsl:element name="Manager">
            <xsl:value-of select="./Field[@name='Manager']"/>
          </xsl:element>
          <xsl:for-each select="key(keyAssessmentID,$AssessmentId)">
            <xsl:element name="Issue">
              <xsl:for-each select="following-sibling::Field[contains(@name,'Issue')]">
                <xsl:element name="{./@name}">
                  <xsl:value-of select="."/>
                </xsl:element>
              </xsl:for-each>
            </xsl:element>
          </xsl:for-each>
        </xsl:element>
      </xsl:for-each>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>