1

以下の入力 XML を目的の出力 XML 形式に変換する必要がありました。このフォーラムの助けを借りて、私は以下のように解決策を得ました:

入力 XML

<?xml version="1.0"?>
<dataset  xmlns="http://developer.cognos.com/schemas/xmldata/1/"  xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
    <item name="Employee Id" />
    <item name="Employee Name" />
    <item name="Department Name" />
</metadata>
<data>
    <row>
      <value>1</value>
      <value Salutation="Dr." >John</value>
      <value>Finance</value>
    </row>
    <row>
      <value>2</value>
      <value Salutation="Mr." >Peter</value>
      <value>Admin</value>
    </row>
</data>
</dataset>

XSLT 変換

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:c="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:template match="/*/c:data">
    <dataset>
        <xsl:apply-templates/>
    </dataset>
</xsl:template>
<xsl:template match="c:row">
    <row>
        <xsl:apply-templates/>
    </row>
</xsl:template>
<xsl:template match="c:row/*">
    <xsl:variable name="vPos" select="position()"/>
    <xsl:element name="{translate($vNames[$vPos], ' ', '_')}">
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>
<xsl:template match="@*">
    <xsl:attribute name="{name()}">
        <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>
</xsl:stylesheet>

目的の出力 XML

<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
    <Employee_Id>1</Employee_Id>
    <Employee_Name Salutation="Dr.">John</Employee_Name>
    <Department_Name>Finance</Department_Name>
</row>
<row>
    <Employee_Id>2</Employee_Id>
    <Employee_Name Salutation="Mr.">Peter</Employee_Name>
    <Department_Name>Admin</Department_Name>
</row>

ただし、このソリューションを破る特別なシナリオに遭遇しました。入力 XML の属性値は、数字、特殊文字、またはスペースで始めることができます。

新しい入力 XML

<?xml version="1.0"?>
<dataset  xmlns="http://developer.cognos.com/schemas/xmldata/1/"  xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
    <item name="1Employee Id" />
    <item name=" Employee Name" />
    <item name="$Department Name" />
</metadata>
<data>
<row>
    <value>1</value>
    <value Salutation="Dr." >John</value>
    <value>Finance</value>
</row>
<row>
    <value>2</value>
    <value Salutation="Mr." >Peter</value>
    <value>Admin</value>
</row>
</data>
</dataset>

name属性値は要素名に変換されるため、要素名を数字またはスペースで開始できないため、上記の変換は失敗します。この場合、これらの文字を要素名の有効な文字に置き換えたり、同じ目的の出力 XML を取得し_たりしたいと考えています。C_

このシナリオをどのように処理しますか?

4

2 に答える 2

1

それは非常に簡単です。translate() 呼び出しの範囲を拡張して、問題のある文字(属性で使用しているが、XML では要素名に使用できない文字) をカバーするだけです。

たとえば、変更...

<xsl:element name="{translate($vNames[$vPos], ' ', '_')}">

...に...

<xsl:element name="{translate($vNames[$vPos], ' 1$', '___')}">

アップデート

OPの明確化に応えて、最初の文字だけを翻訳する方法を次に示します。安全でない最初の文字を含む一時的な要素名が $vName であるとします。$説明のために、安全でない可能性のある唯一の最初の文字として見ているとしましょう。このように、最初の文字を削除して翻訳し、再び追加します...

<xsl:element name="{concat( translate( substring( $vName, 1, 1), '$', '_'),
                            substring( $vName, 2))}" />

...また...

<xsl:element name="{translate( substring( $vName, 1, 1), '$', '_')}{substring( $vName, 2)}" />

ノート

XSLT 2.0 にアップグレードできる場合は、正規表現を使用すると簡単になります...

<xsl:element name="{replace( $vName, '^[$]', '_')}" />
于 2012-10-03T08:08:13.793 に答える
1

ハードコードされた特殊文字を使用しない完全なソリューションを次に示します

<xsl:stylesheet version="1.0"
 xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

    <xsl:variable name="vNames" select="/*/c:metadata/*/@name" />

    <xsl:variable name="vAlpha" select=
    "concat('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
            'abcdefghijklmnopqrstuvwxyz')"/>

    <xsl:template match="/*/c:data">
        <dataset>
            <xsl:apply-templates/>
        </dataset>
    </xsl:template>
    <xsl:template match="c:row">
        <row>
            <xsl:apply-templates/>
        </row>
    </xsl:template>

    <xsl:template match="c:row/*">
        <xsl:variable name="vPos" select="position()"/>
        <xsl:variable name="vChar1" select=
         "translate(substring($vNames[$vPos],1,1),
                    translate(substring($vNames[$vPos],1,1), $vAlpha, ''),
                    '_')"/>
        <xsl:element name=
               "{$vChar1}{translate(substring($vNames[$vPos],2), ' ', '_')}">
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:attribute name="{name()}">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

この変換が提供された XML ドキュメントに適用されると、次のようになります。

<dataset  xmlns="http://developer.cognos.com/schemas/xmldata/1/"  xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
    <metadata>
        <item name="1Employee Id" />
        <item name=" Employee Name" />
        <item name="$Department Name" />
    </metadata>
    <data>
        <row>
            <value>1</value>
            <value Salutation="Dr." >John</value>
            <value>Finance</value>
        </row>
        <row>
            <value>2</value>
            <value Salutation="Mr." >Peter</value>
            <value>Admin</value>
        </row>
    </data>
</dataset>

必要な正しい結果が生成されます。

<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
   <row>
      <_Employee_Id>1</_Employee_Id>
      <_Employee_Name Salutation="Dr.">John</_Employee_Name>
      <_Department_Name>Finance</_Department_Name>
   </row>
   <row>
      <_Employee_Id>2</_Employee_Id>
      <_Employee_Name Salutation="Mr.">Peter</_Employee_Name>
      <_Department_Name>Admin</_Department_Name>
   </row>
</dataset>

説明:

  1. マイケル・ケイによって最初に示された二重翻訳法を使用して、特定の文字セットに属さないすべての文字を識別できます。

  2. 名前の中にスペースに加えて他の不正な文字が含まれている場合、同じ二重変換技術を使用して、そのような (事前に不明な) 文字を目的の有効な文字に置き換えることができます。

于 2012-10-03T12:42:43.827 に答える