如何从一个xml获取一些文档

时间:2012-01-23 16:39:45

标签: xslt

我想从多个级别的xml中获取不同的文档。

我的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <line id="0">
        <Info><![CDATA[Header]]></Info>
        <documentNUM><![CDATA[DOC1]]></documentNUM>
        <Code><![CDATA[AS22]]></Code>
    </line>
    <line id="1">
        <Info><![CDATA[Line]]></Info>
        <Position><![CDATA[1]]></Position>
        <Number><![CDATA[7361]]></Number>
    </line>
    <line id="2">
        <Info><![CDATA[Line]]></Info>
        <Position><![CDATA[2]]></Position>
        <Number><![CDATA[7362]]></Number>
    </line>     
    <line id="3">
        <Info><![CDATA[Header]]></Info>
        <documentNUM><![CDATA[DOC2]]></documentNUM>
        <Code><![CDATA[AS22]]></Code>
    </line>
    <line id="4">
        <Info><![CDATA[Line]]></Info>
        <Position><![CDATA[1]]></Position>
        <Number><![CDATA[3623]]></Number>
    </line> 
    <line id="5">
        <Info><![CDATA[Header]]></Info>
        <documentNUM><![CDATA[DOC1]]></documentNUM>
        <Code><![CDATA[AS22]]></Code>
    </line>
    <line id="6">
        <Info><![CDATA[Line]]></Info>
        <Position><![CDATA[1]]></Position>
        <Number><![CDATA[3623]]></Number>
    </line> 
</document>

从这个xml我应该得到两个文件, 因为它我使用键功能:

<xsl:key name="kNext" match="line[starts-with(Info,'H')]" use="concat(starts-with(Info,'H'), '+', documentNUM)"/>

对于文件3和1行。

需要的结果:

<result>
    <Group>
        <Message>
            <document>
                <documentNUM>DOC1</documentNUM> 
                <Lines>
                    <Line>
                        <LineNumber>1</LineNumber>
                        <Number>7361</Number>
                        <Code>AS22</Code>
                    </Line>
                    <Line>
                        <LineNumber>2</LineNumber>
                        <Number>7362</Number>
                        <Code>AS22</Code>
                    </Line>
                    <Line>
                        <LineNumber>3</LineNumber>
                        <Number>3623</Number>
                        <Code>AS22</Code>
                    </Line>
                </Lines>
            </document>
        </Message>
    </Group>
    <Group>
        <Message>
            <document>
                <documentNUM>DOC2</documentNUM>
            </document> 
                    <Line>
                        <LineNumber>1</LineNumber>
                        <Number>3623</Number>
                        <Code>AS22</Code>
                    </Line>
                </Lines>
        </Message>
    </Group>
</result>

我很难找到线条。对于这两个文件计算相同的行。请给我一些如何得到正确答案的建议。

P.S。如果需要,请更正我的问题。

2 个答案:

答案 0 :(得分:2)

这是一个完整的XSLT 1.0解决方案

<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="kFollowing" match="line[not(documentNUM)]"
  use="generate-id(preceding-sibling::line
                               [documentNUM]
                                          [1]
                  )"/>

 <xsl:key name="kLineByDocNum" match="line"
  use="documentNUM"/>

 <xsl:template match=
  "line
     [documentNUM
    and
      generate-id()
     =
      generate-id(key('kLineByDocNum', documentNUM)[1])
     ]">
   <Group>
    <Message>
      <document>
        <documentNUM>
          <xsl:value-of select="documentNUM"/>
        </documentNUM>
        <Lines>
          <xsl:apply-templates mode="inGroup" select=
          "key('kLineByDocNum', documentNUM)"/>
        </Lines>
      </document>
    </Message>
   </Group>
 </xsl:template>

 <xsl:template match="line" mode="inGroup">
  <xsl:apply-templates mode="inGroup2"
  select="key('kFollowing', generate-id())">
  <xsl:with-param name="pCode" select="Code"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="line" mode="inGroup2">
  <xsl:param name="pCode"/>

  <xsl:variable name="vcurDocNum" select=
  "preceding-sibling::line
            [documentNUM][1]
                  /documentNUM
  "/>
  <xsl:variable name="vPos" select=
  "count(preceding-sibling::line
                [not(documentNUM)]
                  [preceding-sibling::line
                     [documentNUM][1]
                         /documentNUM
                  =
                   $vcurDocNum
                  ]
        ) +1"/>
  <Line>
    <LineNumber><xsl:value-of select="$vPos"/></LineNumber>
    <xsl:copy-of select="Number"/>
    <Code><xsl:value-of select="$pCode"/></Code>
  </Line>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<document>
    <line id="0">
        <Info>Header</Info>
        <documentNUM>DOC1</documentNUM>
        <Code>AS22</Code>
    </line>
    <line id="1">
        <Info>Line</Info>
        <Position>1</Position>
        <Number>7361</Number>
    </line>
    <line id="2">
        <Info>Line</Info>
        <Position>2</Position>
        <Number>7362</Number>
    </line>
    <line id="3">
        <Info>Header</Info>
        <documentNUM>DOC2</documentNUM>
        <Code>AS22</Code>
    </line>
    <line id="4">
        <Info>Line</Info>
        <Position>1</Position>
        <Number>3623</Number>
    </line>
    <line id="5">
        <Info>Header</Info>
        <documentNUM>DOC1</documentNUM>
        <Code>AS22</Code>
    </line>
    <line id="6">
        <Info>Line</Info>
        <Position>1</Position>
        <Number>3623</Number>
    </line>
</document>

产生了想要的正确结果

<Group>
   <Message>
      <document>
         <documentNUM>DOC1</documentNUM>
         <Lines>
            <Line>
               <LineNumber>1</LineNumber>
               <Number>7361</Number>
               <Code>AS22</Code>
            </Line>
            <Line>
               <LineNumber>2</LineNumber>
               <Number>7362</Number>
               <Code>AS22</Code>
            </Line>
            <Line>
               <LineNumber>3</LineNumber>
               <Number>3623</Number>
               <Code>AS22</Code>
            </Line>
         </Lines>
      </document>
   </Message>
</Group>
<Group>
   <Message>
      <document>
         <documentNUM>DOC2</documentNUM>
         <Lines>
            <Line>
               <LineNumber>1</LineNumber>
               <Number>3623</Number>
               <Code>AS22</Code>
            </Line>
         </Lines>
      </document>
   </Message>
</Group>

答案 1 :(得分:0)

这看起来像是一个分组问题。如果您有XSLT 2.0,请使用for-each-group / group-starting-with。那你就不需要钥匙了:

<result>
  <xsl:for-each-group select="line"
       group-starting-with="line[starts-with(Info,'H')]">
    <Group>
      <Message>
        <document>
          <documentNUM>
            <xsl:value-of select="current-grouping-key()/documentNUM" />
          </documentNUM>
        </document>
        <xsl:apply-templates select="current-group()
                          [not(starts-with(Info, 'H'))]" />

如果您想了解更多细节,请与我们联系。