使用XSLT获取密钥之间的价值

时间:2017-03-12 07:44:13

标签: xslt xslt-2.0

我需要在每个密钥之间获取XML文件中的值。例如,我有一个要使用的键列表,每个键都有一个相应的输出元素。密钥可以放在任何地方,没有正确的顺序需要放置密钥。我需要在XSLT 2.0中执行此操作,我不知道如何执行此操作。

键: 元素:

/ OPDH / - ROOT / ELEMENT1 / ABCD

/ EKPH / - ROOT / ELEMENT2 / POIU

/ SGDE / - ROOT / ELEMENT3 / WXYZ

......其他一些钥匙......

注意:键:是BOLD,而Element是ITALIC BOLD。

如果我有这样的示例输入:

1)

<DATA>/OPDH/FLOWING SOLUTION/SGDE/Number0983713/EKPH/Sample test/some other keys/</DATA>

或者可以是:

2)。

<DATA>/some other keys/afdsf/SGDE/Number0983713/some other keys/PIHSAGA/OPDH/FLOWING SOLUTION/some other keys/No exception/EKPH/Sample test/some other keys/</DATA>

预期输出应如下所示:

1

<ROOT>
   <ELEMENT1>
      <ABCD>FLOWING SOLUTION</ABCD>
   </ELEMENT1>
   <ELEMENT2>
      <POIU>Sample test</POIU>
   </ELEMENT2>
   <ELEMENT3>
      <SGDE>Number0983713</SGDE>
   </ELEMENT3>
   ...some other keys...
</ROOT>

2

<ROOT>
  ...some other keys...
   <ELEMENT3>
      <SGDE>Number0983713</SGDE>
   </ELEMENT3>
  ...some other keys...
   <ELEMENT1>
      <ABCD>FLOWING SOLUTION</ABCD>
   </ELEMENT1>
  ...some other keys...
   <ELEMENT2>
      <POIU>Sample test</POIU>
   </ELEMENT2>
  ...some other keys...
</ROOT>

谢谢。

2 个答案:

答案 0 :(得分:0)

以下是使用analyze-string

的部分建议
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf" version="2.0">

    <xsl:param name="keys">
        <element key="/OPDH/">ROOT/ELEMENT1/ABCD</element>
        <element key="/EKPH/">ROOT/ELEMENT2/POIU</element>
        <element key="/SGDE/">ROOT/ELEMENT3/WXYZ</element>
        <element key="/some other keys/">ROOT/FOO/BAR</element>
    </xsl:param>

    <xsl:output indent="yes"/>

    <xsl:variable name="pattern" as="xs:string"
        select="concat('(', string-join($keys/element/@key, '|'), ')', '(.*?)', '(', string-join($keys/element/@key, '|'), ')')"/>

    <xsl:key name="ref" match="element" use="@key"/>

    <xsl:function name="mf:extract" as="element()*">
        <xsl:param name="input" as="xs:string"/>
        <xsl:analyze-string select="$input" regex="{$pattern}">
            <xsl:matching-substring>
                <xsl:if test="position() eq 1">
                    <element path="{key('ref', regex-group(1), $keys)}">
                        <xsl:value-of select="regex-group(2)"/>
                    </element>
                    <xsl:sequence
                        select="mf:extract(substring($input, string-length(concat(regex-group(1), regex-group(2))) + 1))"
                    />
                </xsl:if>
            </xsl:matching-substring>
        </xsl:analyze-string>
    </xsl:function>

    <xsl:template match="DATA">
        <xsl:copy>
            <xsl:sequence select="mf:extract(.)"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这会转换输入

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <DATA>/OPDH/FLOWING SOLUTION/SGDE/Number0983713/EKPH/Sample test/some other keys/</DATA>
    <DATA>/some other keys/afdsf/SGDE/Number0983713/some other keys/PIHSAGA/OPDH/FLOWING SOLUTION/some other keys/No exception/EKPH/Sample test/some other keys/</DATA>
</Root>

包含提取数据和构建路径的元素列表:

    <DATA>
   <element path="ROOT/ELEMENT1/ABCD">FLOWING SOLUTION</element>
   <element path="ROOT/ELEMENT3/WXYZ">Number0983713</element>
   <element path="ROOT/ELEMENT2/POIU">Sample test</element>
</DATA>
    <DATA>
   <element path="ROOT/FOO/BAR">afdsf</element>
   <element path="ROOT/ELEMENT3/WXYZ">Number0983713</element>
   <element path="ROOT/FOO/BAR">PIHSAGA</element>
   <element path="ROOT/ELEMENT1/ABCD">FLOWING SOLUTION</element>
   <element path="ROOT/FOO/BAR">No exception</element>
   <element path="ROOT/ELEMENT2/POIU">Sample test</element>
</DATA>

我不太确定这是否做得对,因为我不确定是什么决定了你提供的两个样本的顺序和内容,以及例如/some other keys/旨在表达。告诉我们结果是否包含您想要的数据,或澄清您的问题以及您展示的样本。一旦我们确定提取了正确的数据,就应该很容易从上述中间结果中生成XML。

答案 1 :(得分:0)

你写的很少关键,所以我认为:

  1. 您的输入文件包含两者

    • 键列表(在KEYS标记中),
    • 实际来源(DATA代码)。
  2. 这两个标记都是源ROOT标记的子标记。

  3. KEYS标记在每一行中包含一对键值和输出路径,其中 应放置此密钥的相应内容。

  4. 假设完整输入为:

    <?xml version="1.0" encoding="UTF-8"?>
    <ROOT>
      <KEYS>
        /OPDH/ - ROOT/ELEMENT1/ABCD
        /EKPH/ - ROOT/ELEMENT2/POIU
        /SGDE/ - ROOT/ELEMENT3/SGDE
      </KEYS>
      <DATA>/OPDH/FLOWING SOLUTION/SGDE/Number0983713/EKPH/Sample test/</DATA>
    </ROOT>
    

    然后你可以按如下方式编写XSLT:

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:output method="xml" encoding="UTF-8" indent="yes" />
    
      <xsl:template match="ROOT">
        <xsl:copy>
          <!-- Divide KEYS into rows -->
          <xsl:variable name="keys_1" select="tokenize(KEYS, '&#xA;')"/>
          <!-- # of rows -->
          <xsl:variable name="nn" select="count($keys_1)"/>
          <!-- Drop 1st and last (empty) row -->
          <xsl:variable name="keys" select="subsequence($keys_1, 2, $nn - 2)"/> 
          <!-- Divide DATA into tokens -->
          <xsl:variable name="data_1" select="tokenize(DATA, '/')"/>
          <!-- # of tokens -->
          <xsl:variable name="nn" select="count($data_1)"/>
          <!-- Drop 1st and last (empty) token -->
          <xsl:variable name="data" select="subsequence($data_1, 2, $nn - 2)"/> 
          <!-- Generate output data for each row from keys -->
          <xsl:for-each select="$keys">
            <!-- Divide the keys row into tokens -->
            <xsl:variable name="parts" select="tokenize(., '/')"/>
            <!-- # of tokens -->
            <xsl:variable name="nn" select="count($parts)"/>
            <!-- Source key - token No 2 (after the 1st '/') -->
            <xsl:variable name="srcKey" select="$parts[2]"/>
            <!-- path - tokens after 'ROOT' -->
            <xsl:variable name="path" select="subsequence($parts, 4)"/> 
            <!-- Open tags given in path -->
            <xsl:for-each select="$path">
              <xsl:text>&#xA;</xsl:text>
              <!-- Spacing -->
              <xsl:variable name="nn" select="position()"/>
              <xsl:value-of select=
                "string-join((for $i in 1 to $nn return '  '), '')"/>
              <!-- Print opening tag -->
              <xsl:value-of select="concat('&lt;', ., '&gt;')"
                disable-output-escaping="yes"/>
            </xsl:for-each>
            <!-- Find position of the source key in data -->
            <xsl:variable name="ind" select="index-of($data, $srcKey)[1]"/>
            <!-- Get data from the next token -->
            <xsl:value-of select="$data[$ind + 1]"/>
            <!-- Close tags given in path -->
            <xsl:for-each select="reverse($path)">
              <xsl:variable name="nn" select="position()"/>
              <!-- Spacing and NewLine - but not for the most inner tag -->
              <xsl:if test="$nn &gt; 1">
                <xsl:text>&#xA;</xsl:text>
                <xsl:value-of select=
                  "string-join((for $i in 1 to last() - $nn + 1 return '  '), '')"/>
              </xsl:if>
              <!-- Print closing tag -->
              <xsl:value-of select="concat('&lt;/', ., '&gt;')"
                disable-output-escaping="yes"/>
            </xsl:for-each>
          </xsl:for-each>
          <xsl:text>&#xA;</xsl:text>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="@*|node()">
        <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
      </xsl:template>
    </xsl:transform>