0

マイクロソフトの従業員の頭の後ろの髪の毛をしっかりとつかみ、硬い表面に頭を強く繰り返し叩くためのてこの力として使用したいと思います。それは私が今この問題を解決するのとほぼ同じくらい気分が良くなるでしょう。

次のような単純なXMLメッセージがあります。

<?xml version="1.0" encoding="utf-8"?>
<message>
    <cmd id="instrument_status">
        <status_id>1</status_id>
    </cmd>
</message>

使用しているデバイスのWebサービスは、そのようなメッセージをいくつか返し、それらを別の形式に変換しています。上記のメッセージの場合、新しい形式は次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<grf:message xmlns:grf="http://www.company.com/schemas/device/version001">
    <grf:messageHeader>
        <grf:messageType>instrumentStatus</grf:messageType>
    </grf:messageHeader>
    <grf:messageBody>
        <grf:instrumentStatusBody>
            <grf:statusId>Running</grf:statusId>
        </grf:instrumentStatusBody>
    </grf:messageBody>
</grf:message>

XMLには、次のようにstatus_id整数値のマッピングがあります。

status-id    Meaning  
=========    =======
0            Ready  
1            Running  
2            NotReady  
3            PoweringUp  
4            PoweringDown  
5            PoweredUp  
6            PoweredDown  
7            Tuning  
8            Error  

Altova XMLSpyを使用すると、XSLTは正しく機能し、正しい出力が得られますが、.NETアプリケーションを実行すると、status_id整数のマッピングが許容可能な列挙型の1つに変換される時点でエラーが発生します。文字列。列挙値を取得する代わりに、MS XSLTプロセッサは空の文字列を返し、出力XMLで空の<status_id/>要素を取得します。

以下は、スペースの量を減らすためにいくつかのセクションが削除された私のXSLTコードです。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:fo="http://www.w3.org/1999/XSL/Format"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:grf="http://www.company.com/schemas/device/version001"
        exclude-result-prefixes="#default">

 <xsl:template match="/">
  <xsl:apply-templates select="message"/>
 </xsl:template>

 <xsl:template match="message">
  <xsl:element name="grf:message">
   <xsl:apply-templates select="/message/cmd/@id"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="/message/cmd/@id">
  <xsl:variable name="_commandType" select="/message/cmd/@id"/>
        <!-- Following line works in Altova XMLSpy, but fails in .NET app. ??? -->
  <xsl:variable name="_statusIdValue" select="/message/cmd/status_id"/>
  <xsl:element name="grf:messageHeader">
   <xsl:element name="grf:messageType">
    <xsl:choose>
     <xsl:when test="$_commandType = 'api_info'">
      <xsl:text>apiInfo</xsl:text>
     </xsl:when>
     <xsl:when test="$_commandType = 'instrument_status'">
      <xsl:text>instrumentStatus</xsl:text>
     </xsl:when>
    </xsl:choose>
   </xsl:element>
  </xsl:element>
  <xsl:element name="grf:messageBody">
   <xsl:choose>
    <xsl:when test="$_commandType = 'api_info'">
     <xsl:element name="grf:apiInfoBody">
      <xsl:element name="grf:apiVersion">
       <xsl:value-of select="/message/cmd/api-version"/>
      </xsl:element>
      <xsl:element name="grf:apiBuild">
       <xsl:value-of select="/message/cmd/api-build"/>
      </xsl:element>
     </xsl:element>
    </xsl:when>
    <xsl:when test="$_commandType = 'instrument_status'">
     <xsl:element name="grf:instrumentStatusBody">
      <xsl:element name="grf:statusId">
       <xsl:choose>
        <xsl:when test="$_statusIdValue = '0'">
         <xsl:text>Ready</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '1'">
         <xsl:text>Running</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '2'">
         <xsl:text>NotReady</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '3'">
         <xsl:text>PoweringUp</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '4'">
         <xsl:text>PoweringDown</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '5'">
         <xsl:text>PoweredUp</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '6'">
         <xsl:text>PoweredDown</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '7'">
         <xsl:text>Tuning</xsl:text>
        </xsl:when>
        <xsl:when test="$_statusIdValue = '8'">
         <xsl:text>Error</xsl:text>
        </xsl:when>
       </xsl:choose>
      </xsl:element>
     </xsl:element>
    </xsl:when>
   </xsl:choose>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

AltovaXMLSpyとMSXSLTプロセッサの両方で同じように動作するXSLT1.0コードはありますか?

ありがとう、

AlarmTripper

4

5 に答える 5

2

注意すべき点の1つは、「message」要素に一致するテンプレートで、これを行うことです。

<xsl:apply-templates select="/message/cmd/@id"/> 

これにより、現在表示されているメッセージに関係なく、実際にはドキュメントルートを基準にしたXMLの最初のメッセージと一致しようとします。現在のノードを基準にして選択していません。あなたの場合、メッセージは1つしかないように見えるので、ここでは問題にはなりませんが、他の場合には問題になります。

また、特に要素の子要素を処理する場合は、属性ではなく要素で一致する方がおそらく一般的です。したがって、おそらく上記の行を代わりにこれに置き換えるでしょう

<xsl:apply-templates select="cmd"/> 

次に、現在これを行う代わりに、それに一致するテンプレートの場合

<xsl:template match="/message/cmd/@id"> 

代わりにこれを行います

<xsl:template match="cmd"> 

次に、このテンプレート内で、変数をより単純なselectステートメントに置き換えてみることができます

<xsl:variable name="_commandType" select="@id"/> 
<xsl:variable name="_statusIdValue" select="status_id"/> 

それが違いを生むかどうかを確認してください。

于 2010-01-09T16:23:17.297 に答える
1

あなたはあなたの変容を過度に複雑にしていますこのかなり単純なスタイルシートを試してください:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.company.com/schemas/device/version001"
>
  <xsl:output indent="yes" encoding="utf-8" />

  <!-- main template / entry point -->
  <xsl:template match="message">
    <message>
      <messageHeader>
        <xsl:apply-templates select="cmd" mode="head" />
      </messageHeader>
      <messageBody>
        <xsl:apply-templates select="cmd" mode="body" />
      </messageBody>
    </message>
  </xsl:template>

  <!-- header templates -->
  <xsl:template match="cmd[@id = 'api_info']" mode="head">
    <messageType>apiInfo</messageType>
  </xsl:template>

  <xsl:template match="cmd[@id = 'instrument_status']" mode="head">
    <messageType>instrumentStatus</messageType>
  </xsl:template>

  <!-- body templates -->
  <xsl:template match="cmd[@id = 'api_info']" mode="body">
    <apiInfoBody>
      <apiVersion><xsl:value-of select="api-version" /></apiVersion>
      <apiBuild><xsl:value-of select="api-build" /></apiBuild>
    </apiInfoBody>
  </xsl:template>

  <xsl:template match="cmd[@id = 'instrument_status']" mode="body">
    <instrumentStatusBody>
      <statusId>
        <xsl:choose>
          <xsl:when test="status_id = 0">Ready</xsl:when>
          <xsl:when test="status_id = 1">Running</xsl:when>
          <xsl:when test="status_id = 2">NotReady</xsl:when>
          <xsl:when test="status_id = 3">PoweringUp</xsl:when>
          <xsl:when test="status_id = 4">PoweringDown</xsl:when>
          <xsl:when test="status_id = 5">PoweredUp</xsl:when>
          <xsl:when test="status_id = 6">PoweredDown</xsl:when>
          <xsl:when test="status_id = 7">Tuning</xsl:when>
          <xsl:when test="status_id = 8">Error</xsl:when>
          <!-- just in case… -->
          <xsl:otherwise>
            <xsl:text>Unknown status_id: </xsl:text>
            <xsl:value-of select="status_id" />
          </xsl:otherwise>
        </xsl:choose>
      </statusId>
    </instrumentStatusBody>
  </xsl:template>

</xsl:stylesheet>

一見不必要な名前空間定義をすべて取り除き (必要に応じて追加し直します)、スタイルシートをデフォルトの名前空間に配置しました。'grf:'これは、実際の結果を変更せずに、すべての要素にプレフィックスを付ける必要がなくなったことを意味します。

<?xml version="1.0" encoding="utf-8"?>
<message xmlns="http://www.company.com/schemas/device/version001">
  <messageHeader>
    <messageType>instrumentStatus</messageType>
  </messageHeader>
  <messageBody>
    <instrumentStatusBody>
      <statusId>Running</statusId>
    </instrumentStatusBody>
  </messageBody>
</message>

適切な状況で適切な要素を出力するために、さまざまな一致式とさまざまなテンプレート モードをどのように使用しているかに注意してください。このようにして、任意<xsl:variable>または<xsl:choose>不必要になり、よりクリーンで保守しやすいスタイルシートが作成されます。

<xsl:element>また、動的な名前で要素を出力したい場合を除き、通常は明示的に定義する必要はありません。それ以外の場合は、要素をすぐに記述できます。

スタイルシートが意図したとおりに動作しない理由をはっきりとは言えず、申し訳ありません。それは私にとってはうまくいき、大丈夫です(っぽい)。

上記で不明な点がありましたら、遠慮なくお尋ねください。

于 2010-01-11T09:46:17.837 に答える
0

OK、次の行を使用して _statusIdValue 変数を割り当てると、コードが XslCompiledTransform クラスで正しく機能することがわかりました。

<xsl:variable name="_statusIdValue" select="msxsl:node-set(/message/cmd/*)/text()"/>

これは、元の行を次のように置き換えます。

<xsl:variable name="_statusIdValue" select="/message/cmd/status_id"/>

ただし、XslCompiledTransform クラスで機能する割り当ては、Altova XMLSpy では機能しません。Altova XMLSpy エディターと XslCompiledTransform クラスの両方で正しく機能する割り当てのバリアントはありますか?

ありがとう、

アラームトリッパー

于 2010-01-08T22:56:00.360 に答える
0

これは非常にひどいコーディングです。.NET で動作しないことを嬉しく思います。スタイルシートを書き直すことをお勧めします。

これを試して:

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:grf="http://www.company.com/schemas/device/version001">

<xsl:template match="message">
   <xsl:variable name="commmand-type" select="cmd/@id"/>
   <xsl:variable name="status-id" select="cmd/status_id/text()"/>

      <grf:message>
         <grf:messageHeader>
            <grf:messageType>
               <xsl:choose> 
                  <xsl:when test="$commmand-type = 'api_info'">apiInfo</xsl:when> 
                  <xsl:when test="$commmand-type = 'instrument_status'">instrumentStatus</xsl:when> 
               </xsl:choose> 
            </grf:messageType>
         </grf:messageHeader>

         <grf:messageBody>
            <xsl:choose> 
               <xsl:when test="$commmand-type = 'api_info'"> 
                  <grf:apiInfoBody>
                     <grf:apiVersion>
                        <xsl:value-of select="cmd/api-version"/>
                     </grf:apiVersion>
                  </grf:apiInfoBody>
                  <grf:apiBuild> 
                     <xsl:value-of select="cmd/api-build"/> 
                  </grf:apiBuild> 
               </xsl:when> 
               <xsl:when test="$commmand-type = 'instrument_status'"> 
                  <grf:instrumentStatusBody>
                     <grf:statusId>
                        <xsl:choose> 
                           <xsl:when test="$status-id = '0'">Ready</xsl:when> 
                           <xsl:when test="$status-id = '1'">Running</xsl:when> 
                           <xsl:when test="$status-id = '2'">NotReady</xsl:when> 
                           <xsl:when test="$status-id = '3'">PoweringUp</xsl:when> 
                           <xsl:when test="$status-id = '4'">PoweringDown</xsl:when> 
                           <xsl:when test="$status-id = '5'">PoweredUp</xsl:when> 
                           <xsl:when test="$status-id = '6'">PoweredDown</xsl:when> 
                           <xsl:when test="$status-id = '7'">Tuning</xsl:when> 
                           <xsl:when test="$status-id = '8'">Error</xsl:when> 
                        </xsl:choose>
                     </grf:statusId>
                  </grf:instrumentStatusBody>
               </xsl:when> 
            </xsl:choose>
        </grf:messageBody>
    </grf:message>
</xsl:template>

</xsl:stylesheet>

私は 1 つだけを使用して<xsl:template>います。適切であると思われる場合はリファクタリングできます。

于 2010-01-08T19:36:29.927 に答える
0

xsltをコーディングしてから長い時間が経ちましたが、私が見ているものに基づいて、この行を変更できる可能性があります:

<xsl:variable name="_statusIdValue" select="/message/cmd/status_id"/>

<xsl:variable name="_statusIdValue" select="/message/cmd/status_id/."/>

これは、要素のコンテンツとノード自体を選択するように指示する必要があります。

値の操作を行い、ノードのテキスト コンテンツが必要な場合のようなものです。あなたは同じことをするでしょう。

たとえば、ステータス ID 番号を吐き出したい場合は、次のように使用できます。

<xsl:value-of select="/message/cmd/status_id/."/>
于 2010-01-08T19:12:41.363 に答える