Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT:合并两个具有不同结构和时间表示形式的日志文件_Xml_Xslt_Merge_Timestamp - Fatal编程技术网

Xml XSLT:合并两个具有不同结构和时间表示形式的日志文件

Xml XSLT:合并两个具有不同结构和时间表示形式的日志文件,xml,xslt,merge,timestamp,Xml,Xslt,Merge,Timestamp,正如迪米特里·诺瓦切夫(Dimitre Novatchev)所问,我创建了一个新问题,因为旧问题的某些部分发生了变化 (链接到旧问题:) 我需要合并两个XML日志文件(最大700MB)。一个日志文件包含带有位置更新的跟踪。另一个日志文件包含收到的消息。可以有多个接收到的消息,而不需要在消息之间进行位置更新,反之亦然 两个日志都有时间戳,包括毫秒(本例中为123): 跟踪日志使用(例如14.7.2012 11:08:07.123) 消息日志使用unix时间戳(例如1342264087123)

正如迪米特里·诺瓦切夫(Dimitre Novatchev)所问,我创建了一个新问题,因为旧问题的某些部分发生了变化

(链接到旧问题:)

我需要合并两个XML日志文件(最大700MB)。一个日志文件包含带有位置更新的跟踪。另一个日志文件包含收到的消息。可以有多个接收到的消息,而不需要在消息之间进行位置更新,反之亦然

两个日志都有时间戳,包括毫秒(本例中为123):

  • 跟踪日志使用(例如14.7.2012 11:08:07.123)
  • 消息日志使用unix时间戳(例如1342264087123)
消息日志中还包括其他元素,但只有路径messageList/message/originator/originatorPosition/timeStamp中的元素是相关的

由于省略了“加速”等附加内容,以下结构略微简化。此附加内容只需与其他邮件/项目一起复制即可

位置跟踪的结构如下所示:


14.7.2012 12:13:05.123
51.12235
9.347214
14.7.2012 12:13:07.456
51.12235
9.347214
消息日志的结构如下所示:


1234
2345
1342264087061
2345
1342264087234
1342264087
42
1234
2345
1342264088064
2345
1342264088254
1342264088
42
进行合并时,应读取时间戳(同时转换/比较“日期”和“时间戳”,包括格式为“14.7.2012 11:08:07.123”的毫秒),并按正确顺序添加所有位置和消息

可以按原样添加位置数据。但是,应该将消息放在标记内,添加标记(基于消息的unix时间,以毫秒为单位),并用标记替换标记。项目被放置在根目录中,与位置跟踪一样

结果可能如下所示:


14.7.2012 12:13:05.123
51.12235
9.347214
14.7.2012 12:13:07.061
1234
2345
1342264087061
2345
1342264087234
1342264087
63
14.7.2012 12:13:07.456
51.12235
9.347214
14.7.2012 12:13:08.064
1234
2345
1342264088064
2345
1342264088254
1342264088
70
还有一些元素在位置日志文件中不包含时间戳(并且没有“FilteredPosition”)。这些项目可以忽略,不需要复制

我非常感谢您对XSLT代码的任何帮助,因为我对这个主题非常陌生…:-/


<?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>
编辑:我添加了一个用于消息时区调整的变量


编辑:修复了属性名称,因此项目将正确排序。

您知道您是仅限于XSLT 1.0还是2.0选项吗?哇。。。非常感谢!:-)工作起来很有魅力。。。只有一个小问题:对话后“消息”的日期提前了一个小时(例如12:00,应该是13:00)。。。有什么想法吗?@SebastianMauthofer我猜是因为时区或夏令时,或者两者兼而有之。我为时区添加了一个变量,并将其设置为1小时。你能测试一下夏季时间戳是否有同样的问题吗?现在我只有“冬季时间戳”:-D…但我会检查一下(如果硬件允许伪造日期)。我想你对时区的看法是对的,因为我在德国,那里的偏移量是1小时(在冬天)。偏移量解决了问题,但正如我刚才看到的,排序仍然不起作用,因为消息日期的格式在一位数小时的情况下缺少前导零,尽管您使用了“[H01]”表示。。。奇怪……做了一些进一步的测试:似乎根本没有@date来对消息项进行排序。当我在输出中添加“”时,位置项上只有一个时间戳…@SebastianMauthofer-Ah。具有错误的属性名称。现在已修复,现在似乎排序正确。