【问题标题】:Merging two different XML log files (trace and messages) using date and timestamp?使用日期和时间戳合并两个不同的 XML 日志文件(跟踪和消息)?
【发布时间】:2012-02-02 17:03:19
【问题描述】:

我需要合并两个 XML 日志文件。一个日志文件包含带有位置更新的跟踪。另一个日志文件包含收到的消息。可以有多个接收到的消息,中间没有位置更新。

两个日志都有时间戳:

  • 跟踪日志使用 (例如 14.7.2012 11:08:07)
  • 消息日志使用 unix 时间戳 (例如 1342264087)

trace 的结构如下:

<item>
        <date>14.7.2012 11:08:07.222</date>
        <MyPosition>
        // Position data
        </MyPosition>
</item>
<item>
        <date>14.7.2012 12:13:07.112</date>
        <MyPosition>
        // Position data
        </MyPosition>
</item>
...

消息的结构是这样的:

<Message>
    // some content of the message
    <subTag>
        <timeStamp>1342264087</timeStamp>
    </subTag>
    // other content of the message
</Message>
<Message>
    // same as above
</Message>
...

在进行合并时,应读取时间戳(同时转换/比较“日期”和“时间戳”)并以正确的顺序添加所有位置和消息。

位置数据可以直接添加。但是,消息应该放在 标记内,应该添加一个 标记(基于消息的 unix 时间),并且 标记应该替换为 标签。

不幸的是不是一个“简单”的合并,尤其是日志文件的大小在 5 MB 到 700 MB 之间... :-/

结果可能如下所示:

<item>
        <date>14.7.2012 11:08:07.222</date>
        <MyPosition>
        // Position data
        </MyPosition>
</item>
<item>
        <date>14.7.2012 11:09:10.867</date>
        <m:Message type="received">
        // content of the <Message>
        </m:Message>
</item>
<item>
        <date>14.7.2012 12:10:11.447</date>
        <m:Message type="received">
        // content of the former <Message>
        </m:Message>
</item>
<item>
        <date>14.7.2012 12:13:07.112</date>
        <MyPosition>
        // Position data
        </MyPosition>
</item>
<item>
        <date>14.7.2012 12:17:11.227</date>
        <m:Message type="received">
        // content of the former <Message>
        </m:Message>
</item>
...

是否有任何工具支持这样的合并?或者有什么简单的方法可以用java解决这个问题?

我非常感谢有关如何解决此问题的任何提示。

【问题讨论】:

  • 我会将它们转换为 excel 表或数据库表。然后你可以按日期/时间排序
  • 这听起来像是 XSL 转换的工作,最好使用 XSLT2,因为它更擅长处理多个输入流。我已重新标记您的帖子以包含 XSLT。我的 XSLT 有点生疏了,但也许 SO 上的 XSLT 专家之一会看到并提供帮助。
  • 我认为主要问题是unix时间戳和日期的比较以及添加包含转换时间戳的日期标签......这也可以使用xslt吗?我在这方面的知识非常有限。
  • 是的,这一切都可以通过 XSLT 实现,但如果您根本不了解 XSLT,那么在没有帮助的情况下这项任务可能会令人生畏。如果您将标签改回来,我建议您至少添加 XSLT。标签timestamplogfiles 充其量是边缘性的——你所拥有的是一个XML 合并任务,对于任何两个XML 文件都是一样的。

标签: xml xslt merge timestamp logfiles


【解决方案1】:

此 XSLT 2.0 转换(为方便起见,包含内联的小消息日志示例):

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:m="some:M" exclude-result-prefixes="xs m">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vDateU0" select="xs:dateTime('1970-01-01T00:00:00')"/>

 <xsl:variable name="vMessages">
    <Message>     // some content of the message
        <subTag>
            <timeStamp>1342264087</timeStamp>
        </subTag>     // other content of the message
    </Message>
    <Message>     // some content of the message2
        <subTag>
            <timeStamp>1342264089</timeStamp>
        </subTag>     // other content of the message2
    </Message>
 </xsl:variable>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/">

  <xsl:variable name="vProcessedMessages">
   <xsl:apply-templates select="$vMessages/*"/>
  </xsl:variable>

  <xsl:variable name="vProcessedTrace">
   <xsl:apply-templates select="/*/*"/>
  </xsl:variable>


  <xsl:perform-sort select="$vProcessedMessages/*|$vProcessedTrace/*">
    <xsl:sort select="xs:dateTime(date)"/>
  </xsl:perform-sort>

 </xsl:template>

 <xsl:template match="Message">
  <xsl:variable name="vUnixDuration" select=
   "concat('PT', */timeStamp, 'S')"/>
  <item>
   <date><xsl:sequence select=
    "$vDateU0 + xs:dayTimeDuration($vUnixDuration)"/>
   </date>
   <m:Message type="received">
     <xsl:sequence select="text()[1]"/>
   </m:Message>
  </item>
 </xsl:template>

 <xsl:template match="date/text()">
  <xsl:variable name="vdatePart" select="substring-before(., ' ')"/>

  <xsl:variable name="vYear" select=
  "substring-after(substring-after($vdatePart, '.'), '.')"/>

  <xsl:variable name="vMonth" select=
  "substring-before(substring-after($vdatePart, '.'), '.')"/>

  <xsl:variable name="vDay" select="substring-before(., '.')"/>

  <xsl:variable name="vFormattedMonth" select=
  "if(string-length($vMonth) eq 1)
    then concat('0', $vMonth)
    else $vMonth
    "/>

  <xsl:variable name="vFormattedDay" select=
  "if(string-length($vDay) eq 1)
    then concat('0', $vDay)
    else $vDay
    "/>

  <xsl:value-of select=
  "concat($vYear,
          '-',
          $vFormattedMonth,
          '-',
          $vFormattedDay,
          'T',
          substring-after(., ' ')
          )"/>
 </xsl:template>
</xsl:stylesheet>

在提供的 Trace-log XML 文档上执行时

<items>
    <item>
        <date>14.7.2012 11:08:07.222</date>
        <MyPosition>         // Position data         </MyPosition>
    </item>
    <item>
        <date>14.7.2012 12:13:07.112</date>
        <MyPosition>         // Position data         </MyPosition>
    </item>
</items>

根据需要合并两个日志

<item>
   <date>2012-07-14T11:08:07</date>
   <m:Message xmlns:m="some:M" type="received">     // some content of the message
        </m:Message>
</item>
<item>
        <date>2012-07-14T11:08:07.222</date>
        <MyPosition>         // Position data         </MyPosition>
    </item>
<item>
   <date>2012-07-14T11:08:09</date>
   <m:Message xmlns:m="some:M" type="received">     // some content of the message2
        </m:Message>
</item>
<item>
        <date>2012-07-14T12:13:07.112</date>
        <MyPosition>         // Position data         </MyPosition>
</item>

注意:在实际情况下,Message-log 将使用document() 函数获取。

【讨论】:

  • 谢谢!我会看看 XSLT 并在我试用后立即报告! :-) 因为我以前从未使用过 XSLT:关于有教程的优秀网站的任何提示?
  • 如果您的 XSLT 知识更先进,我建议您使用 XSLT 3.0,它有一个绝对 100% 符合您要求的 xsl:merge 指令;但这确实是最前沿的(早期草案规范),所以我会避开。 Dimitre 的代码一如既往地完成了这项工作。至于教程,我在使用新语言之前的偏好是买一本书花一天时间看,当然我会推荐自己的!
  • @SebastianMauthofer:请参阅此答案以获取一些建议:stackoverflow.com/a/341589/36305。当我第一次接触 XSLT 时,我买了 Michael Kay 的书并研究了一个月。这就是认真的 XSLT 教育所需要的。
  • 我在使用 Saxon 时遇到问题:transform.xsl 第 39 行出错:FORG0001:xsl:apply-templates 处的持续时间值“PS”(非数字组件)无效(文件: transform.xsl#20) processing /Messages/Message[1] ...看起来,这个错误是由这一行引起的: 我把“PT”改成了“P”,但错误依旧……
  • @SebastianMauthofer:你需要测试你的代码——显然这个错误意味着你的 XPath 表达式 */originator/originatorPosition/timeStamp 选择的不是数字,就像 timestamp 元素的值您最初提供的 XML。要么 XPath 表达式错误,要么 XML 文档的结构和值类型与您向我们显示的不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
相关资源
最近更新 更多