2012-02-07 3 views
1

Dimitre Novatchev의 질문에 따라 이전 질문의 일부분이 변경되어 새로운 질문이 생겼습니다.XSLT : 구조와 시간 표현이 다른 두 개의 로그 파일 병합

(이전 질문에 대한 링크 : Merging two different XML log files (trace and messages) using date and timestamp?)

나는 (7백메가바이트까지) 두 개의 XML 로그 파일을 병합 할 필요가있다. 하나의 로그 파일에 위치 업데이트가있는 추적이 있습니다. 다른 로그 파일에는 수신 된 메시지가 들어 있습니다. 수신 메시지가 여러 개있을 수 있으며 위치 정보를 업데이트하지 않고 반대로 수신 할 수 있습니다.

두 로그 (이 예에서는 123) (밀리 초)을 포함하여 타임 스탬프가 있습니다. (: 08 : 07.123 예를 들어 2012년 7월 14일 11)

  • 는 메시지 로그가 사용

    • 추적 로그는 < 날짜 >를 사용 유닉스 타임 스탬프 < 때문에, timeStamp > (예. 1342264087123)

    이 메시지 로그에 포함 된 다른 < 때문에, timeStamp > 요소도 있지만, 만 messageList/Message/originator/originatorPosition/timeStamp 경로는 관련이 있습니다.

    다음 구조는 "가속도"등과 같은 추가 내용이 빠져 있기 때문에 약간 단순화되었습니다. 이 추가 콘텐츠는 나머지 메시지/항목과 함께 복사하면됩니다.

    같은 위치 추적 구조 같습니다

    <itemList> 
        <item> 
         <date>14.7.2012 12:13:05.123</date> 
         <FilteredPosition> 
          <Latitude>51.12235</Latitude> 
          <Longitude>9.347214</Longitude> 
         </FilteredPosition> 
        </item> 
        <item> 
         <date>14.7.2012 12:13:07.456</date> 
         <FilteredPosition> 
          <Latitude>51.12235</Latitude> 
          <Longitude>9.347214</Longitude> 
         </FilteredPosition> 
        </item> 
    </itemList> 
    

    메시지 로그의 구조는 같다 :

    <messageList> 
        <Message> 
         <messageId>1234</messageId> 
         <originator> 
          <originatorPosition> 
           <nodeId>2345</nodeId> 
           <timeStamp>1342264087061</timeStamp> 
          </originatorPosition> 
          <senderPosition> 
           <nodeId>2345</nodeId> 
           <timeStamp>1342264087234</timeStamp> 
          </senderPosition> 
          <medium></medium> 
         </originator> 
         <MessagePayload> 
          <generationTime> 
           <timeStamp>1342264087</timeStamp> 
           <milliSec>42</milliSec> 
          </generationTime> 
         </MessagePayload> 
        </Message> 
        <Message> 
         <messageId>1234</messageId> 
         <originator> 
          <originatorPosition> 
           <nodeId>2345</nodeId> 
           <timeStamp>1342264088064</timeStamp> 
          </originatorPosition> 
          <senderPosition> 
           <nodeId>2345</nodeId> 
           <timeStamp>1342264088254</timeStamp> 
          </senderPosition> 
          <medium></medium> 
         </originator> 
         <MessagePayload> 
          <generationTime> 
           <timeStamp>1342264088</timeStamp> 
           <milliSec>42</milliSec> 
          </generationTime> 
         </MessagePayload> 
        </Message> 
    </messageList> 
    

    병합 하, 타임 스탬프를 판독한다 (도 변환/"날짜와 시간 형식"밀리 초를 "14.7.2012 11 : 08 : 07.123"형식으로 비교) 및 모든 순위와 메시지가 올바른 순서로 추가됩니다.

    위치 데이터를 그대로 추가 할 수 있습니다. 그러나 메시지는 태그 < 태그태그태그 안에 넣어야하며 (메시지의 유닉스 시간을 기준으로 밀리 초 단위로) 추가되어야하며 < 메시지 > 태그는 <m으로 바꿔야합니다. 메시지 유형 = " 받은 "> 태그. 항목은 위치 추적과 마찬가지로 루트 <itemList>에 배치됩니다.

    결과는 다음과 같을 수 있습니다 :

    <itemList> 
        <item> 
         <date>14.7.2012 12:13:05.123</date> 
         <FilteredPosition> 
          <Latitude>51.12235</Latitude> 
          <Longitude>9.347214</Longitude> 
         </FilteredPosition> 
        </item> 
        <item> 
         <date>14.7.2012 12:13:07.061</date> 
         <m:Message type="received"> 
          <messageId>1234</messageId> 
          <originator> 
           <originatorPosition> 
            <nodeId>2345</nodeId> 
            <timeStamp>1342264087061</timeStamp> 
           </originatorPosition> 
           <senderPosition> 
            <nodeId>2345</nodeId> 
            <timeStamp>1342264087234</timeStamp> 
           </senderPosition> 
           <medium></medium> 
          </originator> 
          <MessagePayload> 
           <generationTime> 
            <timeStamp>1342264087</timeStamp> 
            <milliSec>63</milliSec> 
           </generationTime> 
          </MessagePayload> 
         </m:Message> 
        </item> 
        <item> 
         <date>14.7.2012 12:13:07.456</date> 
         <FilteredPosition> 
          <Latitude>51.12235</Latitude> 
          <Longitude>9.347214</Longitude> 
         </FilteredPosition> 
        </item> 
        <item> 
         <date>14.7.2012 12:13:08.064</date> 
         <m:Message type="received"> 
          <messageId>1234</messageId> 
          <originator> 
           <originatorPosition> 
            <nodeId>2345</nodeId> 
            <timeStamp>1342264088064</timeStamp> 
           </originatorPosition> 
           <senderPosition> 
            <nodeId>2345</nodeId> 
            <timeStamp>1342264088254</timeStamp> 
           </senderPosition> 
           <medium></medium> 
          </originator> 
          <MessagePayload> 
           <generationTime> 
            <timeStamp>1342264088</timeStamp> 
            <milliSec>70</milliSec> 
           </generationTime> 
          </MessagePayload> 
         </m:Message> 
        </item> 
    <itemList> 
    

    위치 로그 파일 내부의 타임 스탬프 (없이 "FilteredPosition")를 포함하지 않는 일부 < 항목 > 요소도 있습니다. 이러한 항목은 무시할 수 있으므로 복사 할 필요가 없습니다.

    XSLT 코드에 대한 도움을 주시면 감사하겠습니다.: -/

  • +0

    XSLT 1.0으로 제한되었거나 2.0 일 경우 옵션을 알고 있습니까? –

    답변

    3
    <?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:xs="http://www.w3.org/2001/XMLSchema" 
        xmlns:m="http://www.example.com/" 
        exclude-result-prefixes="xs" 
        version="2.0"> 
    
        <xsl:output indent="yes" method="xml"/> 
    
        <!-- The two source-documents. --> 
        <xsl:variable name="doc1" select="doc('log1.xml')"/> 
        <xsl:variable name="doc2" select="doc('log2.xml')"/> 
    
        <!-- Timezone adjustment --> 
        <xsl:variable name="timezoneAdjustment" select="1"/> 
    
        <!-- Root template to start the transformation. --> 
        <xsl:template match="/"> 
         <!-- Transform and collect all the elements --> 
         <xsl:variable name="data" as="node()*"> 
          <xsl:apply-templates select="$doc1/itemList/item"/> 
          <xsl:apply-templates select="$doc2/messageList/Message"/> 
         </xsl:variable> 
         <!-- Sort by the timestamp, and discard the wrapper. --> 
         <itemList> 
          <xsl:for-each select="$data"> 
           <xsl:sort select="@timestamp" data-type="number"/> 
           <xsl:copy-of select="item"/> 
          </xsl:for-each> 
         </itemList> 
        </xsl:template> 
    
        <!-- 
         Template to transform <item> elements in the first format. 
         It just parses the date, and adds a wrapper with the timestamp. 
        --> 
        <xsl:template match="item[date]"> 
         <xsl:variable name="dateTimeString" select="date" as="xs:string"/> 
         <xsl:variable name="datePart" select="substring-before($dateTimeString,' ')"/> 
         <xsl:variable name="day" select="xs:integer(substring-before($datePart,'.'))"/> 
         <xsl:variable name="month" select="xs:integer(substring-before(substring-after($datePart,'.'),'.'))"/> 
         <xsl:variable name="year" select="xs:integer(substring-after(substring-after($datePart,'.'),'.'))"/> 
         <xsl:variable name="timePart" select="substring-after($dateTimeString,' ')"/> 
         <xsl:variable name="reformatted" select="concat(format-number($year,'0000'),'-',format-number($month,'00'),'-',format-number($day,'00'),'T',$timePart)"/> 
         <xsl:variable name="timestamp" select="(xs:dateTime($reformatted) - xs:dateTime('1970-01-01T00:00:00') - $timezoneAdjustment * xs:dayTimeDuration('PT1H')) div xs:dayTimeDuration('PT0.001S')"/> 
         <wrapper timestamp="{$timestamp}"> 
          <xsl:copy-of select="self::*"/> 
         </wrapper> 
        </xsl:template> 
    
        <!-- 
         Template to transform <Message> elements in the second log format. 
         It generates an item with the date, and wraps it with the timestamp. 
        --> 
        <xsl:template match="Message[originator/originatorPosition/timeStamp]"> 
         <xsl:variable name="timestamp" select="originator/originatorPosition/timeStamp" as="xs:integer"/> 
         <xsl:variable name="date" select="xs:dateTime('1970-01-01T00:00:00') + $timezoneAdjustment * xs:dayTimeDuration('PT1H') + $timestamp * xs:dayTimeDuration('PT0.001S')"/> 
         <wrapper timestamp="{$timestamp}"> 
          <item> 
           <date> 
            <xsl:value-of select="format-dateTime($date,'[D01].[M01].[Y0001] [H01]:[m01]:[s01].[f001]')"/> 
           </date> 
           <m:Message type="recieved"> 
            <xsl:copy-of select="*"/> 
           </m:Message> 
          </item> 
         </wrapper> 
        </xsl:template> 
    
    </xsl:stylesheet> 
    

    편집 : 나는 메시지에 대한 표준 시간대 조정에 대한 변수를 추가했습니다.

    편집 : 항목이 올바르게 정렬되도록 속성 이름이 수정되었습니다.

    +0

    와우 ... 고마워요! :-) 매력처럼 작동합니다 ... 하나의 작은 문제 : 대화 후 "메시지"의 날짜는 일찍 1 시간입니다 (예 : 13:00 일 때 12:00) ... 아이디어가 있습니까? –

    +0

    @SebastianMauthofer 내 생각에 시간대 또는 일광 절약 시간 또는 둘 다 때문입니다. 시간대 변수를 추가하고 한 시간으로 설정했습니다. 여름 시간 기록표에 동일한 문제가 있는지 테스트해볼 수 있습니까? –

    +0

    지금은 "winter-timestamps"만 얻었습니다 .-D ... 그러나 하드웨어 (위조 된 날짜가 허용되는 경우)를 확인해 보겠습니다. 나는 당신이 타임 존에 맞다고 생각합니다. 나는 독일에 있는데 오프셋이 1 시간 (겨울철)입니다. 오프셋을 사용하면 문제가 해결되지만, 방금 보았 듯이 "[H01]"을 사용했지만 한 자리 숫자의 경우 맨 앞의 0이 없기 때문에 정렬이 여전히 작동하지 않습니다. 표현 ... 이상한 ... –