2

我面临以下问题:

如果我有以下 XML 数据:

<Input>
  <Error>
    <Info> 
      <Code> 111 </Code> 
      <Value>Hello User </Value>
    </Info>
    <Info> 
      <Code>118</Code> 
      <Value>01</Value>
    </Info>
  </Error>
  <Error>
    <Info> 
      <Code> 111 </Code> 
      <Value>Bye User </Value>
    </Info>
    <Info> 
      <Code>118</Code> 
      <Value>01</Value>
    </Info>
  </Error>
  <Error>
    <Info> 
      <Code> 111 </Code> 
      <Value>Dead User </Value>
    </Info>
    <Info> 
      <Code>118</Code> 
      <Value>06</Value>
    </Info>
  </Error>
  <Error>
    <Info> 
      <Code> 111 </Code> 
      <Value>Killed User </Value>
    </Info>
    <Info> 
      <Code>118</Code> 
      <Value>08</Value>
    </Info>
  </Error>
</Input>

知道输出应该类似于

<RecNum>"Value found inside VALUE[2]"</RecNum>
<Error-Description> "Value found inside Value[1]" </Error-Description>

请注意,我并不总是有相同的输出。我可以肯定的是,在每个Error元素中,我每次都有 2 个Info元素和 2 个Value元素。

Error然而,我不知道我在同一个元素中有多少个元素Value[2],所以有时我有 3 个Error元素,它们都有 2 个Info标签,但是这三个错误,它们Info[2]/Value/text()是相同的。

所以上述输入的输出应该是这样的

<Errors>
  <Module>
    <RecNum>1 </RecNum>
    <Error-Description>Hello user </Error-Description>
    <Error-Description>By User </Error-Description>
  </Module>
  <Module>
    <RecNum>6 </RecNum>
    <Error-Description> Dead User </Error-Description>
  </Module>
  <Module>
    <RecNum>8 </RecNum>
    <Error-Description> Killed User </Error-Description>
  </Module>
</Errors>

请注意,我没有值为 02、03、04、05、07、09 等...

我只有 01、06 和 08 的值,有时这些值可能会有所不同。如果你愿意,怎么能做到这样的逻辑?

4

3 回答 3

3

我建议尽量避免xsl:for-each支持真正的 XSLT 在精神上使用模板

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kErrorByVal" match="Error" use="*[2]/Value"/>

 <xsl:template match="/*">
     <Errors>
       <xsl:apply-templates select=
       "*[generate-id()=generate-id(key('kErrorByVal',*[2]/Value)[1])]"/>
     </Errors>
 </xsl:template>

 <xsl:template match="Error">
  <Module>
   <RecNum><xsl:value-of select="*[2]/Value"/></RecNum>
   <xsl:apply-templates select="key('kErrorByVal',*[2]/Value)/*[1]/Value"/>
  </Module>
 </xsl:template>

 <xsl:template match="Value">
  <Error-Description><xsl:value-of select="."/></Error-Description>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<Input>
  <Error>
    <Info>
      <Code> 111 </Code>
      <Value>Hello User </Value>
    </Info>
    <Info>
      <Code>118</Code>
      <Value>01</Value>
    </Info>
  </Error>
  <Error>
    <Info>
      <Code> 111 </Code>
      <Value>Bye User </Value>
    </Info>
    <Info>
      <Code>118</Code>
      <Value>01</Value>
    </Info>
  </Error>
  <Error>
    <Info>
      <Code> 111 </Code>
      <Value>Dead User </Value>
    </Info>
    <Info>
      <Code>118</Code>
      <Value>06</Value>
    </Info>
  </Error>
  <Error>
    <Info>
      <Code> 111 </Code>
      <Value>Killed User </Value>
    </Info>
    <Info>
      <Code>118</Code>
      <Value>08</Value>
    </Info>
  </Error>
</Input>

产生了想要的正确结果:

<Errors>
   <Module>
      <RecNum>01</RecNum>
      <Error-Description>Hello User </Error-Description>
      <Error-Description>Bye User </Error-Description>
   </Module>
   <Module>
      <RecNum>06</RecNum>
      <Error-Description>Dead User </Error-Description>
   </Module>
   <Module>
      <RecNum>08</RecNum>
      <Error-Description>Killed User </Error-Description>
   </Module>
</Errors>
于 2013-05-18T21:57:56.367 回答
0

这是没有任何 if 和变量的相同方法。它检查所有错误值并将它们分组。第二个 for-each 仅在第二个 Info 标记中选择所需的字符串。

这种方法应该是解决问题的快速方法

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>
    <xsl:key name="errors-by-id" match="Error" use="Info[2]/Value" />
        <xsl:template match="Input">
            <xsl:for-each select="Error[count(. | key('errors-by-id', Info[2]/Value)[1]) = 1]">
                <xsl:sort select="Info[2]/Value" />
                <Modul>
                    <RecNum>
                        <xsl:value-of select="Info[2]/Value" />
                    </RecNum>
                <xsl:for-each select="key('errors-by-id', Info[2]/Value)">
                    <Error-Description>
                        <xsl:value-of select="Info[1]/Value"/>
                    </Error-Description>
                </xsl:for-each>
                </Modul>
            </xsl:for-each>
        </xsl:template> 
    </xsl:stylesheet>
于 2013-05-18T21:03:01.703 回答
0

此样式表使用一个键来标识所有Error具有相同Info[2]/Value. 这被称为Muenchian方法。

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

  <xsl:strip-space elements="*"/>
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="error-by-code" match="Error" use="Info[2]/Value"/>

  <xsl:template match="/">
    <Errors>
      <xsl:apply-templates select="Input/Error"/>
    </Errors>
  </xsl:template>

  <xsl:template match="Error">
    <xsl:variable name="error-code" select="Info[2]/Value"/>
    <xsl:if test="generate-id() = generate-id(key('error-by-code', $error-code)[1])">
      <Module>
        <RecNum>
          <xsl:value-of select="Info[2]/Value"/>
        </RecNum>
        <xsl:for-each select="key('error-by-code', $error-code)">
          <Error-Description>
            <xsl:value-of select="Info[1]/Value"/>
          </Error-Description>
        </xsl:for-each>
      </Module>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="utf-8"?>
<Errors>
   <Module>
      <RecNum>01</RecNum>
      <Error-Description>Hello User </Error-Description>
      <Error-Description>Bye User </Error-Description>
   </Module>
   <Module>
      <RecNum>06</RecNum>
      <Error-Description>Dead User </Error-Description>
   </Module>
   <Module>
      <RecNum>08</RecNum>
      <Error-Description>Killed User </Error-Description>
   </Module>
</Errors>
于 2013-05-18T20:39:15.853 回答