BizTalk Mapper: связь между братьями и сестрами

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

<?xml version="1.0" encoding="utf-8"?>
<TestRecords>
  <TestData>
    <Users>
      <User>
        <Id>BG123</Id>
        <Name>Bill Gates</Name>
      </User>
      <User>
    <Id>SN123</Id>
    <Name>Satya Nadella</Name>
  </User>
</Users>
<UserDetails>
  <UserDetail>
    <UserId>SN123</UserId>
    <CompanyName>Microsoft Corp</CompanyName>
  </UserDetail>
  <UserDetail>
    <UserId>
      <UserId>BG123</UserId>
      <CompanyName>Bill Gates Foundation</CompanyName>
    </UserId>
  </UserDetail>
</UserDetails>

Мне нужно сопоставить этот XML со следующим XML:

<?xml version="1.0" encoding="utf-8"?>
<TestRecords>
  <TestData>
    <Users>
      <User>
        <Id>BG123</Id>
        <Name>Bill Gates</Name>
        <CompanyName>Bill Gates Foundation</CompanyName>
      </User>
      <User>
        <Id>SN123</Id>
        <Name>Satya Nadella</Name>
        <CompanyName>Microsoft Corp</CompanyName>
      </User>
    </Users>
  </TestData>
</TestRecords>

Когда я перебираю Users/User, мне нужно найти UserDetail, где UserDetail/UserId равен текущему User/Id

Спасибо и наилучшими пожеланиями

Майкл


person MFox    schedule 19.05.2014    source источник
comment
Это довольно распространенный сценарий. Вы не можете сделать это, используя стандартные функции. Самый простой способ добиться этого — функция Custom XSLT Template. Попробуйте объединить/объединить сообщения Google BizTalk, например. adventuresinsidethemessagebox.wordpress .com/2012/04/01/   -  person FCR    schedule 20.05.2014
comment
спасибо, мне удалось заставить это работать, как описано в сообщении в блоге   -  person MFox    schedule 20.05.2014
comment
@FCR На самом деле это возможно со стандартными функтоидами, но иногда это может быть не самым эффективным способом. Смотрите мой ответ ниже. P.S. Сообщение в блоге, на которое вы указали, принадлежит моему коллеге по работе.   -  person Dijkgraaf    schedule 22.05.2014


Ответы (2)


Если вы не хотите использовать Custom XSLT, как это предлагает FCR, единственный другой вариант, когда у вас есть разные циклические структуры, — это иметь промежуточную схему и две карты.

UserIn в UserInt

Что производит

<TestRecords>
    <TestData>
        <Users>
            <User>
                <Id>BG123</Id>
                <Name>Bill Gates</Name>
                <UserDetails>
                    <UserID>SN123</UserID>
                    <CompanyName>Microsoft Corp</CompanyName>
                </UserDetails>
                <UserDetails>
                    <UserID>BG123</UserID>
                    <CompanyName>Bill Gates Foundation</CompanyName>
                </UserDetails>
            </User>
            <User>
                <Id>SN123</Id>
                <Name>Satya Nadella</Name>
                <UserDetails>
                    <UserID>SN123</UserID>
                    <CompanyName>Microsoft Corp</CompanyName>
                </UserDetails>
                <UserDetails>
                    <UserID>BG123</UserID>
                    <CompanyName>Bill Gates Foundation</CompanyName>
                </UserDetails>
            </User>
        </Users>
    </TestData>
</TestRecords>

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

UserInt to UserOut

Однако это станет очень неэффективным, если второй список большой.

person Dijkgraaf    schedule 22.05.2014
comment
Да, я не думал об этом. Немного странное решение, кстати =) - person FCR; 22.05.2014

Это распространенный шаблон поиска в xslt, а также есть возможность использовать xsl:key для создания индекса, который может повысить производительность при работе с большими документами. Обратитесь сюда, если вам нужно преобразовать .btm в xslt.

(Кроме того, я предполагаю, что в последнем элементе UserDetails/UserDetail нет двойной оболочки UserId):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

   <xsl:output indent="yes"/>

   <xsl:key name="userLookup" 
            match="/TestRecords/TestData/UserDetails/UserDetail" use="UserId"/>

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

   <!--i.e.match only Users in the first Users/User tree. Actually the explicit
       ancestor qualifier is redundant because of the other suppress template -->
   <xsl:template match="User[ancestor::Users]">
      <User>
         <xsl:copy-of select="child::*" />
         <CompanyName>
            <xsl:value-of select="key('userLookup', Id)/CompanyName"/>
        </CompanyName>
      </User>   
   </xsl:template>

   <!--Suppress the second userdetails part of the tree entirely -->
   <xsl:template match="UserDetails" />
</xsl:stylesheet>

Поиграйте здесь

person StuartLC    schedule 22.05.2014