2015-10-23 3 views
0

У меня есть входящее XML-сообщение, и каждое сообщение имеет другую схему. Я хочу преобразовать этот запрос в другую схему, используя C# .Net как мой XSLT-процессор. Вот упрощенный сценарий ситуации, которая у меня есть.Как преобразовать XML с помощью XSLT на основе внешнего параметра?

Входящий запрос:

<?xml version="1.0" encoding="utf-8"?> 
<Request xmlns="http://www.example.com/api"> 
    <SourceId>SourceId1</SourceId> 
    <RequestId>RequestId1</RequestId> 
    <StatusEvent> 
    <TenderId>TenderId1</TenderId> 
    <EventCode>TENDER_STARTED</EventCode> 
    </StatusEvent> 
</Request> 

Перевести на:

<?xml version="1.0" encoding="utf-8"?> 
<TransactionStatus xmlns="http://www.example1.com/api"> 
    <RequestId>RequestId1</RequestId> 
    <TransactionId>TenderId1</TransactionId> 
    <Event>TRANSACTION_STARTED</Event> 
</TransactionStatus> 

Входящий запрос:

<?xml version="1.0" encoding="utf-8"?> 
<Response xmlns="http://www.example.com/api"> 
    <SourceId>SourceId1</SourceId> 
    <RequestId>RequestId1</RequestId> 
    <TenderCreated> 
    <TenderId>TenderId1</TenderId> 
    </TenderCreated> 
</Response> 

Перевести на:

<?xml version="1.0" encoding="utf-8"?> 
<TransactionStarted xmlns="http://www.example1.com/api"> 
    <RequestId>RequestId1</RequestId> 
    <TransactionId>TenderId1</TransactionId> 
</TransactionStarted> 

Вот XSLT настоящее время я использую для достижения выше результата,

 <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns0="http://www.example.com/api" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="ns0 xs"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 
    <xsl:template match="text()"/> 
    <xsl:template match="ns0:StatusEvent[1]"> 
    <TransactionStatus 
     xmlns="http://www.example1.com/api"> 
     <RequestId> 
     <xsl:value-of select="//ns0:RequestId"/> 
     </RequestId> 
     <TransactionId> 
     <xsl:value-of select="ns0:TenderId"/> 
     </TransactionId> 
     <Event> 
     <xsl:value-of select="ns0:EventCode"/> 
     </Event> 
    </TransactionStatus> 
    </xsl:template> 

    <xsl:template match="ns0:TenderCreated[1]"> 
    <TransactionStarted 
     xmlns="http://www.example1.com/api"> 
     <RequestId> 
     <xsl:value-of select="//ns0:RequestId"/> 
     </RequestId> 
     <TransactionId> 
     <xsl:value-of select="ns0:TenderId"/> 
     </TransactionId> 
    </TransactionStarted> 
    </xsl:template> 
    </xsl:stylesheet> 

Так вот два вопроса, у меня есть,

  1. Для текущего сценария я получаю правильный результат, но, есть ли лучший способ достичь этого?
  2. Для некоторых входящих запросов, я хочу выбрать шаблон на основе внешнего параметра, как мне это достичь?

Update: Больше разъяснения по второму вопросу,

например: В 2 Входящий запрос я мог бы TenderUpdated вместо TenderCreated и для этого я хочу, чтобы перевести это в любом TransactionUpdated или TransactionCanceled зависит от внешнего параметра строки.

так Если входящий запрос, как,

<?xml version="1.0" encoding="utf-8"?> 
<Response xmlns="http://www.example.com/api"> 
    <SourceId>SourceId1</SourceId> 
    <RequestId>RequestId1</RequestId> 
    <TenderUpdated> 
    <TenderId>TenderId1</TenderId> 
    </TenderUpdated> 
</Response> 

И передаваемый параметр Update, перевести

<?xml version="1.0" encoding="utf-8"?> 
    <TransactionUpdated xmlns="http://www.example1.com/api"> 
     <RequestId>RequestId1</RequestId> 
     <TransactionId>TenderId1</TransactionId> 
     <Update/> 
    </TransactionUpdated> 

И если передаваемый параметр Cancel, перевести

<?xml version="1.0" encoding="utf-8"?> 
     <TransactionCanceled xmlns="http://www.example1.com/api"> 
      <RequestId>RequestId1</RequestId> 
      <TransactionId>TenderId1</TransactionId> 
      <Cancel/> 
     </TransactionCanceled> 

Этом упрощенный сценарий, фактическое сообщение имеет больше xml тег и TransactionUpdated и TransactionCanceled сильно отличается.

+0

С корневой вход, имеющий '' Я не понимаю, почему ваша таблица стилей будет делать то, что вы говорите, что делает, как ни 'StatusEvent 'или' RequestId' выбирать или сопоставлять элементы во входном пространстве имен, они выбирают или сопоставляют элементы без пространства имен. –

+0

Я упростил сценарий, так что, возможно, пропустил бит, сделав это по умолчанию для пространства имен, правильно? – Glk

+1

С процессором XSLT 2.0, таким как Saxon 9, вы можете установить 'xpath-default-namespace =" http://www.example.com/api "', но с .NET 'XslCompiledTransform' вам нужно будет использовать префикс' ns0' вы указали на все свои имена элементов, например 'Ns0: StatusEvent'. –

ответ

1

Если вы знаете, что все элементы результата должны находиться в пространстве имен http://www.example1.com/api, тогда вы можете поместить это на xsl:stylesheet, например.

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="http://www.example1.com/api" 
    xmlns:ns0="http://www.example.com/api" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="ns0 xs"> 

Что касается параметра, объявим его как

<xsl:param name="transactionName" select="'Updated'"/> 

и когда вы хотите, чтобы создать элемент, используя этот параметр не используется конечный элемент, но вместо xsl:element:

<xsl:element name="Transaction{$transactionName}">...</xsl:element> 

К сожалению, в XSLT 1.0 использование ссылок параметров или переменных внутри шаблонов не разрешено, поэтому для обработки условия вы можете написать только сопоставление шаблона по имени элемента, а затем вам нужно использовать xsl:choose/xsl:when для обработки различных имен элементов. Вот пример того, что вы можете, мы надеемся расширить:

<xsl:transform 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0" 
    xmlns:api="http://www.example.com/api" 
    xmlns="http://www.example1.com/api" 
    exclude-result-prefixes="api"> 

    <xsl:param name="transactionName" select="'Update'"/> 

    <xsl:output indent="yes"/> 

    <xsl:template match="api:Response"> 
     <xsl:element name="Transaction{$transactionName}"> 
      <xsl:apply-templates select="api:RequestId | api:TenderUpdated/api:TenderId"/> 
      <xsl:choose> 
       <xsl:when test="$transactionName = 'Update'"> 
        <Update/> 
       </xsl:when> 
       <xsl:when test="$transactionName = 'Cancel'"> 
        <Cancel/> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="api:RequestId"> 
     <RequestId> 
      <xsl:apply-templates/> 
     </RequestId> 
    </xsl:template> 

    <xsl:template match="api:TenderId"> 
     <TransactionId> 
      <xsl:apply-templates/> 
     </TransactionId> 
    </xsl:template> 
</xsl:transform> 

Online на http://xsltransform.net/94rmq5R.

Если между форматами ввода существует много различий, то у меня может возникнуть соблазн обработать их разными таблицами стилей. Если это невозможно, возможно, имеет смысл разветвиться в шаблоне для корневого и использовать режимы на шаблонах, чтобы отличить обработку, например.

<xsl:template match="api:Response"> 
      <xsl:choose> 
       <xsl:when test="$transactionName = 'Update'"> 
        <xsl:apply-templates select="." mode="update"/> 
       </xsl:when> 
       <xsl:when test="$transactionName = 'Cancel'"> 
        <xsl:apply-templates select="." mode="cancel"/> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="api:Response" mode="update"> 
     <TransactionUpdate> 
     <xsl:apply-templates select="api:Foo | api:Bar" mode="update"/> 
     <Update/> 
     <TransactionUpdate> 
    </xsl:template> 
    <!-- now add templates for the other elements and for other mode(s) here --> 
+0

тело TransactionUpdated или TransactionCanceled может отличаться, поэтому вместо определения элемента один раз и просто изменить имя, можем ли мы сделать отдельный шаблон и выбрать на основе переданного параметра? – Glk

+0

Можете ли вы отредактировать свой вопрос и показать два разных элемента и два разных результата, которые вы хотите создать на основе параметра? –

+0

Я обновил свой вопрос, просто любопытно, можем ли мы сделать что-то вроде '', чтобы найти шаблон на основе параметра в Xslt версии 1.0? – Glk

Смежные вопросы