Выберите последний узел из нескольких родителей - PullRequest
0 голосов
/ 10 января 2012

У меня есть следующая структура XML

<root>
 <entries>
  <object id="1">
   <value name="valName1">Text</value>
   <value name="valName2">Text</value>
   <value name="valName3">Text</value>
  </object>
  <object id="2">
   <value name="valName1">Text</value>
  </object>
  <object id="1">
   <value name="valName1">OtherText</value>
   <value name="valName2">Text</value>
  </object>
 </entries>
</root>

Я хочу закончить с:

object: 1
valName1: OtherText
valName2: Text
valName3: Text

object: 2
valName1: Text

Важно, чтобы он возвращал последние данные для узла значения, но он долженполучить все значения из узлов, где они существуют ...

Есть идеи?

Ответы [ 2 ]

1 голос
/ 10 января 2012

Этого можно достичь в чистом XSLT путем группировки. В XLST 1.0 вы бы использовали мюнхенскую группировку, и в этом случае вам понадобится две группы. Во-первых, вы должны сгруппировать по object , что означает определение ключа для поиска object элементов по ID

<xsl:key name="objects" match="object" use="@id" />

И для поиска первого элемента в каждой группе (т. Е. Уникального идентификатора объекта) вы должны использовать ключ следующим образом:

<xsl:apply-templates 
   select="//object[generate-id() = generate-id(key('objects', @id)[1])]" />

Затем вы группируете по значению , что означает определение ключа для поиска значения элементов в их соответствующих объектах элементах

<xsl:key name="values" match="value" use="concat(../@id, '|', @name)" />

В этом случае вам действительно нужен последний элемент в каждой группе, поэтому вы должны использовать ключ следующим образом:

<xsl:apply-templates 
   select="//object[@id = $id]
      /value[generate-id() 
       = generate-id(key('values', concat($id, '|', @name))[last()])]">

Вот полный XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" indent="yes"/>
   <xsl:key name="objects" match="object" use="@id" />
   <xsl:key name="values" match="value" use="concat(../@id, '|', @name)" />

   <xsl:template match="/">
      <xsl:apply-templates select="//object[generate-id() = generate-id(key('objects', @id)[1])]" />
   </xsl:template>

   <xsl:template match="object">
      <xsl:variable name="id" select="@id" />
      <xsl:value-of select="concat('object: ', $id, '&#13;')" />
      <xsl:apply-templates select="//object[@id = $id]/value[generate-id() = generate-id(key('values', concat($id, '|', @name))[last()])]">
         <xsl:sort select="@name" />
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="value">
      <xsl:value-of select="concat(@name, ':', ., '&#13;')" />
   </xsl:template>
</xsl:stylesheet>

При применении к предоставленному входному XML выводится следующий текст:

object: 1
valName1:OtherText
valName2:Text
valName3:Text
object: 2
valName1:Text
0 голосов
/ 10 января 2012

Это, конечно, возможно, но я бы сказал, что вы неправильно используете XML несколькими способами.Насколько я понимаю, теги id, как правило, уникальны, и порядок поступления файлов не должен иметь значения.Тем не менее, это легко возможно с Python.

Используйте словарь.Просто просмотрите файл и добавьте объекты в словарь, как только вы их найдете.«Объект», который вы добавляете, будет фактически иметь идентификатор объекта в качестве индекса и сам будет пустым словарем.Отслеживайте текущий объект, в котором вы находитесь, и ищите каждый тег значения, добавляя имена значений и их содержимое в словарь текущего объекта.Это позволит отслеживать последние найденные данные.

В качестве альтернативы вы можете подождать до завтра, когда у меня будет время написать это для вас (тест в правительстве AP завтра).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...