XSLT-преобразование, объединяющее значения - PullRequest
0 голосов
/ 15 октября 2019

У меня есть входной документ XML, который отформатирован следующим образом:

<Label>
    <Person>
        <Hash>12345</Hash>
        <Id>123123</Id>
        <Firstname>John</Firstname>
        <Lastname>Doe</Lastname>
        <Category>Business</Category>
    </Person>
    <Person>
        <Hash>12345</Hash>
        <Id>456789<Id>
        <Fistname>John</Firstname>
        <Lastname>Doe</Lastname>
        <Category>Information</Category>
    </Person>
</Label>

Я хочу объединить все подчиненные узлы из Person, что приведет к следующему выходному документу:

<Label>
    <Person>
        <Hash>12345</Hash>
        <Id>123123, 456789</Id>
        <Firstname>John</Firstname>
        <Lastname>Doe</Lastname>
        <Category>Business, Information</Category>
    <Person>
</Label>

Таким образом, на самом деле объединение всех узлов от человека к одному. Желательно объединять одни и те же значения в одно значение, но это не обязательно. Также допустимо следующее преобразование:

<Label>
    <Person>
        <Hash>12345, 12345</Hash>
        <Id>123123, 456789</Id>
        <Firstname>John, John</Firstname>
        <Lastname>Doe, Doe</Lastname>
        <Category>Business, Information</Category>
    <Person>
</Label>

Любое предложение о том, как этого добиться, приветствуется!

Преобразование предпочтительно в xslt 1.0

Ответы [ 2 ]

0 голосов
/ 15 октября 2019
var x = require('xml-js')

//let xml = '**your xml string**'
let xml = '<Label> <Person> <Hash>12345</Hash>        <Id>123123</Id>        <Firstname>John</Firstname>        <Lastname>Doe</Lastname>        <Category>Business</Category>    </Person>    <Person>        <Hash>12345</Hash>        <Id>456789</Id>        <Firstname>John</Firstname>        <Lastname>Doe</Lastname>       <Category>Information</Category>    </Person></Label>'

jd = JSON.parse(x.xml2json(xml, {compact:true})) //converting xml to json

//Putting all values in first index

jd.Label.Person[0].Hash._text = jd.Label.Person.map((ele)=>{return ele.Hash._text}).join(",")

jd.Label.Person[0].Id._text = jd.Label.Person.map((ele)=>{return ele.Id._text}).join(",")

jd.Label.Person[0].Firstname._text = jd.Label.Person.map((ele)=>{return ele.Firstname._text}).join(",")

jd.Label.Person[0].Lastname._text = jd.Label.Person.map((ele)=>{return ele.Lastname._text}).join(",")

jd.Label.Person[0].Category._text = jd.Label.Person.map((ele)=>{return ele.Category._text}).join(",")

let options = {compact: true, ignoreComment: true};

let all = jd.Label.Person[0]

jd.Label.Person=[] //Deleting all the records

jd.Label.Person.push(all) //Inserting single record contains all

let newXml = x.json2xml(jd, options) //json to xml again

console.log(newXml)
//newXml is the new generated xml
0 голосов
/ 15 октября 2019

Чтобы упростить поиск значений полей, вы можете определить ключ.

  <xsl:key name="field" match="Person/*" use="local-name()" />

Затем вам просто нужно выбрать дочерние узлы первого элемента Person и для каждого из них. используйте ключ для ввода значений ...

  <xsl:for-each select="key('field', local-name())">
    <xsl:if test="position() > 1">, </xsl:if>
    <xsl:value-of select="." />
  </xsl:for-each>

Попробуйте этот XSLT, который оставляет дубликаты в

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

  <xsl:key name="field" match="Person/*" use="local-name()" />

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

  <xsl:template match="Person[1]/*">
    <xsl:copy>
      <xsl:for-each select="key('field', local-name())">
        <xsl:if test="position() > 1">, </xsl:if>
        <xsl:value-of select="." />
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Person[position() > 1]" />
</xsl:stylesheet>

Если вы действительно хотите удалить дубликаты, вам нужно будет использоватьМюнхенская группировка. Это означает объявление второго ключа

 <xsl:key name="fieldAndValue" match="Person/*" use="concat(local-name(), ':', .)" />

И для получения различных значений измените xsl:for-each следующим образом:

<xsl:for-each select="key('field', local-name())[generate-id() = generate-id(key('fieldAndValue', concat(local-name(), ':', .))[1])]">

Попробуйте этот XSLT тоже

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:key name="field" match="Person/*" use="local-name()" />
  <xsl:key name="fieldAndValue" match="Person/*" use="concat(local-name(), ':', .)" />

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

  <xsl:template match="Person[1]/*">
    <xsl:copy>
      <xsl:for-each select="key('field', local-name())[generate-id() = generate-id(key('fieldAndValue', concat(local-name(), ':', .))[1])]">
        <xsl:if test="position() > 1">, </xsl:if>
        <xsl:value-of select="." />
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Person[position() > 1]" />
</xsl:stylesheet>

Конечно, если бы вы могли использовать XSLT 2.0, вы могли бы сделать это намного проще ...

<xsl:template match="Person[1]/*">
  <xsl:copy>
    <xsl:value-of select="distinct-values(key('field', local-name()))" separator=", " />
  </xsl:copy>
</xsl:template>

РЕДАКТИРОВАТЬ : Если вы не можете использовать xsl:key, измените xsl:for-each (в первом XSLT, который не удаляет дубликаты) к этому ....

 <xsl:for-each select="//Person/*[local-name() = local-name(current())]">

При этом сохраняются дубликаты. Удаление дубликатов без ключа возможно, но, вероятно, слишком много проблем, чем стоит ....

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