使用xsl检查XML字符串中的值

时间:2019-02-21 11:02:50

标签: xml xslt

我是这个论坛的新手,甚至是xsl的新手。 我需要帮助来解决XML代码的一个小问题:请看一下下面的结构。

*********************************
<ProductRevision id="id45" **************>
  <ApplicationRef **************/>
  <UserData *********>
  <UserValue title="title1" value="11111 000 000"/>
  <UserValue title="object_name" value="test name1"/>
  </UserData>
  </ProductRevision>
<ProductRevision id="id50" ***********>
  <ApplicationRef **************/>
  <UserData id="id46">
  <UserValue title="title1" value="22222 000 000"/>
  <UserValue title="object_name" value="test name2"/>
  </UserData>
  </ProductRevision>
*******************************************
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id45">
  <ApplicationRef **************/>
  <UserData ********>
  <UserValue title="ds5_amont" type="int" value="3"/>
  <UserValue title="ds5_cavities" type="int" value="2"/>
  </UserData>
  </GeneralRelation>
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id50">
  <ApplicationRef ***********/>
  <UserData **********>
  <UserValue title="ds5_amont" type="int" value="2"/>
  <UserValue title="ds5_cavities" type="int" value="3"/>
  </UserData>
  </GeneralRelation>

如您所见,ProductRevision节点包含一个id值;此值标识两个对应的GeneralRelation节点,其中包含UserValues ds5_amont ds5_cavities 。 我使用以下.xsl代码片段来显示所有ProductRevision节点的title1和object_name的值:

<xsl:for-each select="//plm:ProductRevision[@subType = 'XXXXX']">
  <xsl:variable name="part" select="./plm:UserData/plm:UserValue[@title='object_name']/@value" />
  <xsl:variable name="identnr" select="./plm:UserData/plm:UserValue[@title='title1']/@value" />
<Row>
  <Cell ss:StyleID="s73">
  <Data ss:Type="String">
  <xsl:value-of select="$part"/>
  </Data>
  </Cell>
  <Cell ss:StyleID="s73">
  <Data ss:Type="String">
  <xsl:value-of select="$identnr"/>
  </Data> 
  </Cell> 
</Row> 

现在,对于每个ProductRevision,我需要显示相应的 ds5_amont ds5_cavities 值,这些值包含在 id45 标识的相应节点中和 id50 值。这些属性必须打印在显示$ part和$ identnr变量的单元格旁边。 到目前为止,我还找不到解决方案,我们将不胜感激! 谢谢!

编辑

对不起,我无法在2秒内学习如何在您的论坛上重现Excel表。结果应该像这样: 对于每个产品版本,应该有一行显示 object_name **** title1 **** ds5_amont **** ds5_cavities 再次抱歉,希望它足够清楚;-)

3 个答案:

答案 0 :(得分:1)

使用`00000000 <__ltdf2>:` ` 0: 4e56 0000 linkw %fp,#0` `4: 4878 0001 pea 1 <__ltdf2+0x1>` ` 8: 2f2e 0014 movel %fp@(20),%sp@-` ` c: 2f2e 0010 movel %fp@(16),%sp@-` `10: 2f2e 000c movel %fp@(12),%sp@-` `14: 2f2e 0008 movel %fp@(8),%sp@-` `18: 61ff 0000 0000 bsrl 1a <__ltdf2+0x1a>` `1e: 4e5e unlk %fp` ` 20: 4e75 rts` 处理器,您可以利用EXSLT libxslt扩展功能。

请考虑以下简化示例:

XML

str:tokenize()

XSLT 1.0 + EXSLT

<root>
  <ProductRevision id="id45">
    <ApplicationRef/>
    <UserData>
      <UserValue title="title1" value="11111 000 000"/>
      <UserValue title="object_name" value="test name1"/>
    </UserData>
  </ProductRevision>
  <ProductRevision id="id50">
    <ApplicationRef/>
    <UserData id="id46">
      <UserValue title="title1" value="22222 000 000"/>
      <UserValue title="object_name" value="test name2"/>
    </UserData>
  </ProductRevision>
  <GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id45">
    <ApplicationRef/>
    <UserData>
      <UserValue title="ds5_amont" type="int" value="453"/>
      <UserValue title="ds5_cavities" type="int" value="452"/>
    </UserData>
  </GeneralRelation>
  <GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id50">
    <ApplicationRef/>
    <UserData>
      <UserValue title="ds5_amont" type="int" value="502"/>
      <UserValue title="ds5_cavities" type="int" value="503"/>
    </UserData>
  </GeneralRelation>
</root>

结果

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="relation" match="GeneralRelation" use="str:tokenize(@relatedRefs, ' ')" />

<xsl:template match="/root">
    <table>
        <xsl:for-each select="ProductRevision">
            <Row>
                <!-- ProductRevision -->
                <Cell>
                    <xsl:value-of select="UserData/UserValue[@title='object_name']/@value"/>
                </Cell>
                <Cell>
                    <xsl:value-of select="UserData/UserValue[@title='title1']/@value"/>
                </Cell>
                <!-- GeneralRelation -->
                <xsl:variable name="relation" select="key('relation', concat('#', @id))" />
                <Cell>
                    <xsl:value-of select="$relation/UserData/UserValue[@title='ds5_amont']/@value"/>
                </Cell>
                <Cell>
                    <xsl:value-of select="$relation/UserData/UserValue[@title='ds5_cavities']/@value"/>
                </Cell>
            </Row> 
        </xsl:for-each>
    </table>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

您要处理在其GeneralRelation属性列表中具有当前@id元素的ProductRevision值的@relatedRefs元素。在XSLT 1.0中,您可以使用containscurrent函数,如下所示:

/root
  /GeneralRelation
    [contains
       (concat(@relatedRefs,' '),
        concat('#',current()/@id,' ')
       )
    ]

此输入:

<root>
    <ProductRevision id="id45">
        <ApplicationRef />
        <UserData>
            <UserValue title="title1" value="11111 000 000" />
            <UserValue title="object_name" value="test name1" />
        </UserData>
    </ProductRevision>
    <ProductRevision id="id50">
        <ApplicationRef />
        <UserData id="id46">
            <UserValue title="title1" value="22222 000 000" />
            <UserValue title="object_name" value="test name2" />
        </UserData>
    </ProductRevision>
    <GeneralRelation id="id49" subType="TestType"
        relatedRefs="#id2 #id45">
        <ApplicationRef />
        <UserData>
            <UserValue title="ds5_amont" type="int" value="453" />
            <UserValue title="ds5_cavities" type="int" value="452" />
        </UserData>
    </GeneralRelation>
    <GeneralRelation id="id49" subType="TestType"
        relatedRefs="#id2 #id50">
        <ApplicationRef />
        <UserData>
            <UserValue title="ds5_amont" type="int" value="502" />
            <UserValue title="ds5_cavities" type="int" value="503" />
        </UserData>
    </GeneralRelation>
</root>

这种转变

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

    <xsl:variable name="vGeneralRelation" 
        select="/root/GeneralRelation" />

    <xsl:template match="text()|GeneralRelation" />
    <xsl:template match="root">
        <table>
            <xsl:apply-templates />
        </table>
    </xsl:template>

    <xsl:template match="ProductRevision">
        <Row>
            <xsl:apply-templates
                select="*|$vGeneralRelation[
                    contains(concat(@relatedRefs,' '),
                        concat('#',current()/@id,' '))]/*" />
        </Row>
    </xsl:template>

    <xsl:template
        match="UserValue[@title[.='object_name' or .='title1' or .='ds5_cavities' or .='ds5_amont']]">
        <Cell>
            <xsl:value-of select="@value" />
        </Cell>
    </xsl:template>
</xsl:stylesheet>

产生此输出

<?xml version="1.0" encoding="utf-8"?>
<table>
   <Row>
      <Cell>11111 000 000</Cell>
      <Cell>test name1</Cell>
      <Cell>453</Cell>
      <Cell>452</Cell>
   </Row>
   <Row>
      <Cell>22222 000 000</Cell>
      <Cell>test name2</Cell>
      <Cell>502</Cell>
      <Cell>503</Cell>
   </Row>
</table>

http://xsltransform.net/6qaFCEU上查看工作示例

答案 2 :(得分:0)

谢谢大家的贡献。 最后,这是我使用的解决方案。我猜您的解决方案都是非常复杂且专业的解决方案,但是对于像我这样的初学者来说,有必要简化代码,以便甚至可以轻松识别错误。 但我可以告诉您,我将对这些解决方案进行大量研究! 首先,通过 subType 属性识别正确的 ProductRevision 节点;然后,在ProductRevision节点的上下文中显示两个变量,并将ID存储在 pid 变量中:

    <xsl:template match="//plm:ProductRevision[@subType='DS5_PartRevision']">

    <xsl:variable name="part" select="./plm:UserData/plm:UserValue[@title='object_name']/@value" />
    <xsl:variable name="identnr" select="./plm:UserData/plm:UserValue[@title='ds5_s_serien_identnr']/@value" />
    <xsl:variable name="pid" select="@id"/>

    <Row>

        <Cell ss:StyleID="s73">
            <Data ss:Type="String">
                <xsl:value-of select="$part"/>
            </Data>
        </Cell>
        <Cell ss:StyleID="s73">
            <Data ss:Type="String">
                <xsl:value-of select="$identnr"/>
            </Data>  
        </Cell> 

处理完第一个ProductRevision节点后,检查所有 GeneralRelation 节点;为每个节点创建变量 relref ,并存储 relatedRefs 属性值的一部分。仅存储“#”(空格-#)之后的值:

<xsl:for-each select="/plm:PLMXML/plm:GeneralRelation">
            <xsl:variable name="relref" select="substring-after(@relatedRefs,' #')"/>

            <xsl:choose>
                <xsl:when test="$relref=$pid">
                    <Cell ss:StyleID="s73">
                        <Data ss:Type="String">
                            <xsl:value-of select="./plm:UserData/plm:UserValue[@title='ds5_amont']/@value"/>
                        </Data>  
                    </Cell>
                    <Cell ss:StyleID="s73">
                        <Data ss:Type="String">
                            <xsl:value-of select="./plm:UserData/plm:UserValue[@title='ds5_cavities']/@value"/>
                        </Data>  
                    </Cell>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>

    </Row>

对于每个GeneralRelation节点,比较 pid relref 的值:如果它们匹配,则在GeneralRelation的上下文中获取两个属性的值节点(因此使用./plm/表示法),并将其显示在(相应ProductRevision的)正确的行中。