2

MySQLクエリブラウザを使用したXMLプロデュースがあります。XSLTを適用して結果をWordテーブルに出力しようとしています。レコードごとに1つのテーブル。

これが私のXMLのサンプルです

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ROOT SYSTEM "Nessus.dtd">
<ROOT>
    <row>
      <field name="Niveau">Critique</field>
      <field name="Name">Apache 2.2 &lt; 2.2.15 Multiple Vulnerabilities</field>
    </row>
    <row>
      <field name="Niveau">Critique</field>
      <field name="VulnName">Microsoft Windows 2000 Unsupported Installation Detection</field>
    </row>
    <row>
      <field name="Niveau">Haute</field>
      <field name="VulnName">CGI Generic SQL Injection</field>
    </row>
</ROOT>

XLSTの場合、私はfor-eachselectを実行する必要があることをすでに知っています

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

    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
<xsl:for-each select="ROOT/row">
  Niveau : <xsl:value-of select="????"/>
  Name   : <xsl:value-of select="????"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

このループを実行すると、ファイルと同じ数の空のテーブルが<row></row>表示されます。

しかし、私は正しい「select-ofselect=」を作成する方法を見つけていません。私は運がなくて次のことを試みました。

<xsl:value-of select="@name"/>
<xsl:value-of select="name"/>
<xsl:value-of select="@row/name"/>
<xsl:value-of select="row/@name"/>
<xsl:value-of select="@ROOT/row/name"/>

そして、私が思い出せない他のいくつか。結果のファイルで値を取得するためにリクエストを作成するために何が必要か考えてみてください。

私はちょうど試しました:

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

    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
<xsl:for-each select="ROOT/row">
  Niveau : <xsl:value-of select="field/@Niveau"/>
  Name   : <xsl:value-of select="field/@name"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

そしてそれはこれを出力します:

NIVEAU :  
NAME   : name

NIVEAU :  
NAME   : Niveau

NIVEAU :  
NAME   : Niveau

私はこの出力が欲しいです:

NIVEAU : Critique
NAME   : Apache 2.2 &lt; 2.2.15 Multiple Vulnerabilities

NIVEAU : Critique
NAME   : Microsoft Windows 2000 Unsupported Installation Detection

NIVEAU : Haute
NAME   : CGI Generic SQL Injection

どんな助けでもいただければ幸いです。

ありがとうございました。

アップデート

今このXSLTで

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

  <xsl:output method="text"/>

  <xsl:strip-space elements="*"/>

  <xsl:template match="row">
    <xsl:text>NIVEAU : </xsl:text>
    <xsl:value-of select="field[@name = 'Niveau']"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:text>NAME   : </xsl:text>
    <xsl:value-of select="field[@name = 'Name']"/>
    <xsl:text>&#xa;&#xa;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

私はこの出力を取得します:

<?xml version="1.0"?>
NIVEAU : 
NAME   : Apache 2.2 &lt; 2.2.15 Multiple Vulnerabilities

NIVEAU : Critique
NAME   : Microsoft Windows 2000 Unsupported Installation Detection

NIVEAU : Haute
NAME   : CGI Generic SQL Injection

ご覧のとおり、最初のフィールドは空です。私は正直にそれと一緒に住んで手動でそれを埋めることができましたが、なぜこれが起こっているのかを理解できれば私はとても幸せです:)

アップデート

使用<xsl:value-of select="field[@name = 'foo']"/>することで、私が望んでいた価値が得られました。MS Wordテンプレート内で(私にとって)使いやすかったので、for-eachを保持しました。

4

3 に答える 3

3

for-eachXSLTでは一般的にコードの臭いです。ほとんどの場合、for-eachループではなく、テンプレートが必要です。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
    <root>
        <xsl:apply-templates/>
    </root>
</xsl:template>

<xsl:template match="field">
<xsl:value-of select="@name"/> : <xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>

このテンプレートは、次の出力を生成します。

<root>
    
      Niveau : Critique
      name : Apache 2.2 &lt; 2.2.15 Multiple Vulnerabilities
    
    
      Niveau : Critique
      name : Microsoft Windows 2000 Unsupported Installation Detection
    
    
      Niveau : Haute
      name : CGI Generic SQL Injection
    
</root>

XSLTは、この使用パターン用に設計されました。多くxsl:templateの場合、ソースのごく一部を照合し、他のテンプレートを再帰的に適用します。このパターンで最も重要で一般的なテンプレートは、出力をコピーするIDテンプレートです。これは、読む必要のあるXSLTコーディングパターンに関する優れたチュートリアルです。

アップデート

以下は、テキスト出力を生成する完全なソリューションです(XML出力ではなく、それが必要と思われるため)。xslがこれに最適な言語かどうかはわかりませんが、機能します。

for-each使用する場所は、最長の名前の長さを決定するための並べ替えのみであることに注意してください。テンプレートとパターンマッチングを使用selectして、他のすべてのループを暗黙的にします。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable name="newline"><xsl:text>
</xsl:text></xsl:variable>

  <!-- determine the maximum length of the "name" field so we can pad with spaces for all shorter items -->
  <xsl:variable name="max_name_len">
    <xsl:for-each select="ROOT/row/field/@name">
      <xsl:sort select="string-length(.)" data-type="number" order="descending"/>
      <xsl:if test="position() = 1">
        <xsl:value-of select="string-length(.)"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <!-- for each row, apply templates then add a blank line -->
  <xsl:template match="row">
    <xsl:apply-templates/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <!-- for each field, apply template to name and add value, followed by a newline -->
  <xsl:template match="field">
    <xsl:apply-templates select="@name"/> : <xsl:value-of select="concat(., $newline)"/>
  </xsl:template>


  <!-- for each name, uppercase and pad with spaces to the right -->
  <xsl:template match="field/@name">
    <xsl:call-template name="padright">
      <xsl:with-param name="text">
        <xsl:call-template name="toupper">
          <xsl:with-param name="text" select="."/>
        </xsl:call-template>
      </xsl:with-param>
      <xsl:with-param name="len" select="$max_name_len"/>
    </xsl:call-template>
  </xsl:template>


  <!-- Utility function: uppercase a string -->
  <xsl:template name="toupper">
    <xsl:param name="text"/>
    <xsl:value-of select="translate($text, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
  </xsl:template>

  <!-- Utility function: pad a string to desired len with spaces on the right -->
  <!-- uses a recursive solution -->
  <xsl:template name="padright">
    <xsl:param name="text"/>
    <xsl:param name="len"/>
    <xsl:choose>
      <xsl:when test="string-length($text) &lt; $len">
        <xsl:call-template name="padright">
          <xsl:with-param name="text" select="concat($text, ' ')"/>
          <xsl:with-param name="len" select="$len"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

このスタイルシートは、次の出力を生成します。

NIVEAU : Critique
NAME   : Apache 2.2 < 2.2.15 Multiple Vulnerabilities

NIVEAU : Critique
NAME   : Microsoft Windows 2000 Unsupported Installation Detection

NIVEAU : Haute
NAME   : CGI Generic SQL Injection
于 2012-11-05T20:45:21.980 に答える
1

を実行する<xsl:for-each select="ROOT/row">と、ループ内の現在のコンテキストがrow要素になります。したがって、フィールド名にアクセスするには、たとえば、を記述する必要があります<xsl:value-of select="field/@name"/>

XMLにはいくつかのフィールドが含まれているため、フィールドを反復処理するためにXSLTファイルをいくらか拡張するか、(Francis Avilaが提案したように)テンプレートを作成する必要があります。ただし、どちらの方法でも問題ありません。2つのアプローチの専門用語は、それぞれ「プル」と「プッシュ」です。

そしてもちろん、最終的には単語テーブルを生成したいのでw:trw:tc要素などを生成する必要があります。

于 2012-11-05T20:56:27.207 に答える
0

このスタイルシートはあなたに正確にあなたの望む出力を与えるでしょう

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

  <xsl:output method="text"/>

  <xsl:strip-space elements="*"/>

  <xsl:template match="row">
    <xsl:text>NIVEAU : </xsl:text>
    <xsl:value-of select="field[@name eq 'Niveau']"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:text>NAME   : </xsl:text>
    <xsl:value-of select="field[@name eq 'VulnName']"/>
    <xsl:text>&#xa;&#xa;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

これは、入力xmlと出力テキストに非常に固有です。たとえば、「Niveau」または「VulnName」以外の<field>子はレポートから削除されます。<row>より一般的なソリューションは次のようになります。

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

  <xsl:output method="text"/>

  <xsl:template match="field">
    <xsl:value-of select="concat(upper-case(@name),': ',.)"/>
  </xsl:template>

</xsl:stylesheet>

このソリューションは、目的の出力の空白のフォーマットと完全には一致しませんが、すべての可能なフィールドをキャプチャします。

于 2012-11-05T23:15:45.773 に答える