5

次のようなデータを含むXMLファイルを翻訳したいと思います。

<FlatData>
    <Details1_Collection>
        <Details1 Customer1="Customer" Total1="3" />
        ...
    </Details1_Collection>
</FlatData>

私が興味を持っているデータは、それぞれの属性とその値ですDetails1。問題は、これらの属性が、翻訳するすべてのXMLファイルで必ずしも同じになるとは限らないことです。また、次のような処理が可能な汎用XSLがDetails1必要です。

<Details1 Customer1="Customer" Total1="3" />
<Details1 Name="Jim" Age="14" Weight="180" />
<Details1 Date="2009-07-27" Range="1-5" Option1="True" />

これらの違いDetails1は、同じソースXMLファイルではなく、異なるファイルで発生します。ただし、それぞれに同じXSLを使用したいと思います。

こんなもの<xsl:value-of select="@attribute_name"/>が必要だと思っていたの@attribute_nameですが、どんな属性があるのか​​事前にわからないときはどうすればいいのでしょうか?また、属性名を取得するにはどうすればよいですか?上記のソースXMLを次のように分解したいと思います。

<Details1>
    <Customer1>Customer</Customer1>
    <Total1>3</Total1>
</Details1>

編集:回答ありがとうございます!ただし、次の出力以上を取得するのに問題があります。

<?xml version="1.0" encoding="UTF-8"?>
<FlatData>
<Details1_Collection></Details1_Collection>
</FlatData>

私はラヴィニオとイェルンホルストマンの両方の答えを試し、2つを組み合わせようとしました。私はこのコマンドを実行します:

msxsl.exe -o output.xml input.xml transform.xsl

邪魔になっているのは、入力ファイルの名前空間だと思います。

<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport">
4

6 に答える 6

4

入力XMLの一部であるMicrosoftSQLReporting Services 2008名前空間のために、問題が増加しました。<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport">それがそんなに重要な線だと最初は気づかなかった。名前空間コメントを提供してくれたPavelMinaevに感謝します。次のXSLは、必要なデータを抽出するために機能しました。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="EXQC005">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="/">
    <xsl:for-each select="a:Report/a:FlatData/a:Details1_Collection/a:Details1">
      <xsl:element name="{name(.)}">
        <xsl:for-each select="@*">
          <xsl:element name="{name(.)}">
            <xsl:value-of select="."/>
          </xsl:element>
        </xsl:for-each>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

ラヴィニオが提案したapply-templatesスタイルを使用するために、これをクリーンアップしようと思います。ループ内のコードを提供してくれたJörnHorstmannにも感謝します。Reporting Servicesレポートが、スキーマURLではなく、レポートの名前に設定された値で最初にダンプされる理由を理解することは興味深いでしょう。select="@*"for-eachxmlns

このXSLを改良しながら、この回答を更新し続けます。

編集: これは名前空間に依存しないバージョンです。ReportingServicesからのレポートごとに、明らかに異なる名前空間が存在するためです。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="/">
    <xsl:for-each select="*[local-name()='Report']/*[local-name()='FlatData']/*[local-name()='Details1_Collection']/*[local-name()='Details1']">
      <Details>
        <xsl:for-each select="@*">
          <xsl:element name="{name(.)}">
            <xsl:value-of select="."/>
          </xsl:element>
        </xsl:for-each>
      </Details>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
于 2009-07-28T17:13:26.423 に答える
3

"@*"次の例のように、を使用してすべての属性を参照できます。

  • <xsl:value-of select="@*"/>
  • <xsl:apply-templates select="@*"/>
  • <xsl:template match="@*">

<xsl:element name="">コンストラクトを使用して、任意の名前の新しい要素を作成できます。関数またはname()local-name()、特定の属性の名前を返します。

あなたがやりたいことをするために、これらの線に沿って何かを試してください:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <FlatData>
            <Details1_Collection>
                <xsl:apply-templates select="FlatData/Details1_Collection/Details1"/>
            </Details1_Collection>
        </FlatData>
    </xsl:template>
    <xsl:template match="Details1">
        <Details1>
            <xsl:apply-templates select="@*"/>
        </Details1>
    </xsl:template>
    <xsl:template match="@*">
        <xsl:element name="{name()}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>
于 2009-07-27T21:33:16.663 に答える
3

名前空間の問題を解決するには (両方の回答で)、プレフィックス付きの名前空間宣言をXLST に追加します。

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

次に、すべての XPath 式でそれを使用して要素を修飾します。次に例を示します。

<xsl:template match="//r:Details1">
于 2009-07-28T16:56:28.660 に答える
2

この変換はあなたが望む結果をもたらしますか?

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

    <xsl:output method="xml" indent="yes" encoding="utf-8" />

    <xsl:template match="//Details1">
        <Details1>
            <xsl:for-each select="@*">
                <xsl:element name="{name(.)}"><xsl:value-of select="." /></xsl:element>
            </xsl:for-each>
        </Details1>
    </xsl:template>

</xsl:stylesheet>
于 2009-07-27T21:38:09.057 に答える
0

Jörn Horstmann の回答を記述する別の方法 (Details1、Details2 などでこれを行う必要がある場合) は次のようになります。

<xsl:template match="//Details1 | //Details2 | //whatever">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="@*">
  <xsl:element name="{name(.)}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>
于 2009-07-27T21:45:52.457 に答える
0

おそらく最も簡単な方法は次のとおりです。

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

  <xsl:template match="/">
    <FlatData>
      <xsl:copy-of select="//Details1" />
    </FlatData>
  </xsl:template>
</xsl:stylesheet>
于 2009-07-28T16:42:29.933 に答える