简体   繁体   English

使用XSLT将非结构化(Adlib)XML转换为结构化XML,将相似的节点分组

[英]Unstructured (Adlib) XML to structured XML using XSLT, grouping similar nodes

I've got an unstructured Adlib XML file, which contains data in the following format : 我有一个非结构化的Adlib XML文件,其中包含以下格式的数据:

<record>
    ...
    <dimension.type>height</dimension.type>
    <dimension.type>width</dimension.type>
    <dimension.type>height</dimension.type>
    <dimension.type>width</dimension.type>
    <dimension.type>depth</dimension.type>
    <dimension.notes>without frame</dimension.notes>
    <dimension.notes>without frame</dimension.notes>
    <dimension.notes>with frame</dimension.notes>
    <dimension.notes>with frame</dimension.notes>
    <dimension.notes>with frame</dimension.notes>
    <dimension.value>28.0</dimension.value>
    <dimension.value>47.9</dimension.value>
    <dimension.value>41.4</dimension.value>
    <dimension.value>62.9</dimension.value>
    <dimension.value>8.0</dimension.value>
    ...
</record>

What I would like to do is transform this to the following format : 我想做的就是将其转换为以下格式:

<record>
    ...
    <dimension>
       <notes>without frame</notes>
       <height>28.0</height>
       <width>47.9</width>
    </dimension>
    <dimension>
       <notes>with frame</notes>
       <height>41.4</height>
       <width>62.9</width>
       <depth>8.0</depth>
    </dimension>
    ...
</record>

However I'm kind of stuck, since these nodes refer to information in other nodes at the same position. 但是,我有点受阻,因为这些节点引用同一位置的其他节点中的信息。 I did come up with the following XSLT: 我确实提出了以下XSLT:

<xsl:template match="dimension.value">
  <xsl:variable name="pos" select="position()"/>
  <dimension>
  <xsl:choose>
    <xsl:when test="../dimension.type[$pos] = 'height'">
      <height><xsl:value-of select="."/></height>
    </xsl:when>
    <xsl:when test="../dimension.type[$pos] = 'width'">
      <width><xsl:value-of select="."/></width>
    </xsl:when>
    <xsl:when test="../dimension.type[$pos] = 'depth'">
      <depth><xsl:value-of select="."/></depth>
    </xsl:when>
  </xsl:choose>
  <notes>
    <xsl:value-of select="../dimension.notes[$pos]"/>
  </notes>
  </dimension>
</xsl:template>

Which produces data in the format : 产生以下格式的数据:

<dimension>
   <height>28.0</height>
   <notes>without frame</notes>
</dimension>
<dimension>
    <width>47.9</width>
    <notes>without frame</notes>
</dimension>
<dimension>
    <height>41.4</height>
    <notes>with frame</notes>
</dimension>
<dimension>
    <width>62.9</width>
    <notes>with frame</notes>
</dimension>
<dimension>
    <depth>8.0</depth>
    <notes>with frame</notes>
</dimension>

But that doesn't do the grouping on note part, which would make processing the result a bit easier (now I solve this in code, but there has to be a way for XSLT to do it, right?). 但这并不能对注释部分进行分组,这会使处理结果变得容易一些(现在我在代码中解决了这个问题,但是XSLT必须有一种方法可以这样做,对吗?)。 Any help (pointers to relevant information or relevant XSLT snippets) would be greatly appreciated... 任何帮助(指向相关信息或相关XSLT代码段的指针)将不胜感激...

BTW I translated parts of the XML/XSLT to make it easier to understand, the when:test actually checks for Dutch descriptions and transforms them into the equivalent English tags... 顺便说一句,我翻译了XML / XSLT的一部分以使其更容易理解,when:test实际上检查荷兰语描述并将其转换为等效的英语标记...

Here is an XSLT 1.0 solution: 这是XSLT 1.0解决方案:

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

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

  <xsl:template match="record">
    <xsl:copy>
      <xsl:apply-templates select="dimension.notes[1]" mode="group"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="dimension.notes" mode="group">
    <dimension>
      <notes>
        <xsl:value-of select="."/>
      </notes>
      <xsl:apply-templates select="."/>
    </dimension>
    <xsl:apply-templates select="following-sibling::dimension.notes[not(. = current())][1]" mode="group"/>
  </xsl:template>

  <xsl:template match="dimension.notes">
    <xsl:variable name="pos">
      <xsl:number/>
    </xsl:variable>
    <xsl:apply-templates select="../dimension.type[position() = $pos]">
      <xsl:with-param name="pos" select="$pos"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="following-sibling::dimension.notes[1][. = current()]"/>
  </xsl:template>

  <xsl:template match="dimension.type">
    <xsl:param name="pos"/>
    <xsl:element name="{.}">
      <xsl:value-of select="../dimension.value[position() = $pos]"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Here is some example using XSLT 2.0: 这是一些使用XSLT 2.0的示例:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">

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

  <xsl:template match="record">
    <xsl:copy>
      <xsl:for-each-group select="dimension.notes" group-adjacent=".">
        <dimension>
          <notes>
            <xsl:value-of select="current-grouping-key()"/>
          </notes>
          <xsl:apply-templates select="current-group()"/>
        </dimension>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="dimension.notes">
    <xsl:variable name="pos" as="xs:integer">
      <xsl:number/>
    </xsl:variable>
    <xsl:apply-templates select="../dimension.type[position() eq $pos]">
      <xsl:with-param name="pos" select="$pos"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="dimension.type">
    <xsl:param name="pos"/>
    <xsl:element name="{.}">
      <xsl:value-of select="../dimension.value[position() eq $pos]"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

I am not sure it solves your problem as the "..." in your sample might require more complex coding, depending on what kind of elements exactly can occur there and what you want to do with them. 我不确定它是否可以解决您的问题,因为示例中的“ ...”可能需要更复杂的编码,具体取决于在那里可能确切地发生什么类型的元素以及您想对它们进行什么处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM