XSL:匹配多属性标记上的ID

时间:2013-10-26 23:16:21

标签: xml xslt xml-parsing xslt-1.0

我在这方面工作了一段时间,但无法找到任何类型的工作解决方案。这一切都在xml版本1中。

第一个名为dog_info.xml的文件有类似的东西:

<?xml version"1.0" encoding="UTF-8"?>
<dog_info version="2" dog_num="2" update_time="2013-15-05T14:80:00Z">
   <dog_list xml: lang="en">
      <dog id="1" name="Nikki" desc="Black with brown spots"/>
      <dog id="2" name="Zulu" desc="Oreo color"/>
      <dog id="3" name="Tyler" desc="brown dog"/>
      <dog id="4" name="Sally" desc="milk color"/>
      <dog id="5" name="Joe" desc="brown and grey color"/>
   </dog_list>
   <dog_list xml:lang="piggylatin">
      <dog id="1" name="Nikky" desc="black spots with black and brown spots"/>
      <dog id="2" name="apples" desc="green, red or blue apples"/>
      <dog id="3" name="Taylor" desc="yellow dog"/>
      <dog id="4" name="Susan" desc="a dog"/>
      <dog id="5" name="Jason" desc="a cat"/>
   </dog_list>
</dog_info>

第二个名为profile.xml的文件有这样的东西:

<?xml version="1.0" encoding="UTF-8"?>
<profile>
   <animal-helper>
      <animal>
         <category>
            <rule>
               <value>1</value>
               <deny />
            </rule>
            <rule>
               <value>2</value>
               <deny />
            </rule>
         </category>
      </animal>
   </animal-helper>
</profile>

第三个文件就是我写的,但是卡住了。它应该是一个xsl,我可以解析成一个html来显示信息。

profile.xml的值为1且拒绝。如果它是deny,它将与dog_list.xml中的id匹配并检索名称和desc。与任何其他否认相同。

没有<allow />个标签,只有<deny />。因此,允许dog_list.xml中所有其余的id。并且应该在html上列出它自己的类别。

我还要注意看看语言是不是“piggylatin”还是“en”它会默认为“en”。任何帮助将不胜感激。

编辑:

实际文件非常大,用于工作。所以我不得不重新创建一些类似于我需要它的东西。

我有类似的东西:

...


<xsl:for-each select="$HELPER/animal/category/rule[name=false()]">
   <xsl:variable name="currentValue" select="value/text()"/>
   <xsl:variable name="dogValue" select="$DOG_LIST"/> 
   <xsl:for-each select="$dogValue/dog[@id = $currentValue]">
      <xsl:apply-templates/><xsl:if test="position() != last()"><xsl:text disable-output-escaping="yes"><![CDATA[<br />]]></xsl:text></xsl:if>
   </xsl:for-each>
</xsl:for-each>
...

编辑2:

上面代码的片段是html表(deny部分)的一部分。看起来应该是这样的:

“拒绝”
尼克
祖鲁

“允许”
泰勒
萨利

因此“Deny”找到值1和2,与id 1和2匹配,并返回名称。 并且“允许”发现id 3,4,5,(因为1和2)被拒绝并返回名称。

<deny />元素的目的是挑选被拒绝的狗并列出它们,然后在此基础上,允许另一个未被拒绝的“id”。

我编写的代码的上述部分将包含两部分。 “拒绝”部分和“允许”部分。 Allowed部分必须测试最初未为<deny />选择的其他“id”。

2 个答案:

答案 0 :(得分:2)

您可以反转逻辑并循环遍历第一个文件中的 dog 元素,而不是循环遍历规则元素,首先只选择具有相应< strong>拒绝,然后再次挑选那些没有。

要创建规则元素的外观,您可以定义变量,如此

<xsl:variable name="lookup" select="document('profile.xml')/profile/animal-helper/animal/category/rule" />

要查找被拒绝的 dog 元素,您可以执行此操作(假设您位于第一个文件中的 dog_info 元素)

<xsl:apply-templates select="dog[@id=$lookup[deny]/value]" />

要获得不否认的,只需这样做

<xsl:apply-templates select="dog[not(@id=$lookup[deny]/value)]" />

就“语言”而言,您可以从选择带有所需语言的 dog_info 元素开始

<xsl:apply-templates select="dog_list[@xml:lang='en']" />

试试这个XSLT

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

   <xsl:variable name="lookup" select="document('profile.xml')/profile/animal-helper/animal/category/rule" />

   <xsl:template match="/*">
      <xsl:apply-templates select="dog_list[@xml:lang='en']" />
   </xsl:template>

   <xsl:template match="dog_list">
      DENY:<br />
         <xsl:apply-templates select="dog[@id=$lookup[deny]/value]" />
      APPROVE:<br />
         <xsl:apply-templates select="dog[not(@id=$lookup[deny]/value)]" />
    </xsl:template>

     <xsl:template match="dog">
         <xsl:value-of select="@name" />
         <br />
   </xsl:template>
</xsl:stylesheet>

这应输出以下内容

  DENY:<br>
  Nikki<br>
  Zulu<br>
  APPROVE:<br>
  Tyler<br>
  Sally<br>
  Joe<br>

答案 1 :(得分:2)

首先:忘记<xsl:for-each>存在。它使事情变得困难。你(几乎)从不需要它。

编写模板并使用模板匹配,专注于选择节点将模板应用于,而不是编写嵌套循环。

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

  <xsl:variable name="profile" select="document('profile.xml')" />
  <xsl:variable name="denied" select="$profile//animal/category/rule[deny]/value" />

  <xsl:template match="/*">
    <html>
      <head><!-- ... --></head>
      <body>
        <h1>Denied</h1>
        <ul>
          <xsl:apply-templates select="dog_list/dog[@id = $denied]" />
        </ul>

        <h1>Allowed</h1>
        <ul>
          <xsl:apply-templates select="dog_list/dog[not(@id = $denied)]" />
        </ul>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="dog">
    <li><xsl:value-of select="@name" /></li>
  </xsl:template>
</xsl:stylesheet>

关于语言和默认语言,使用参数和键:

<xsl:param name="defaultLang" select="'en'" />
<xsl:param name="displayLang" select="'piggylatin'" />

<!-- index dogs by their language and ID -->
<xsl:key name="kDogByLang" match="dog" select="concat(../@xml:lang, '/', @id)" />


<!-- ...and replace the dog template with this: -->

<xsl:template match="dog">
  <xsl:variable name="default" select="key('kDogByLang', concat($defaultLang, '/', @id))" />
  <xsl:variable name="display" select="key('kDogByLang', concat($displayLang, '/', @id))" />

  <xsl:choose>
    <!-- if this is the correct language, output it -->
    <xsl:when test="generate-id() = generate-id($display)">
      <li><xsl:value-of select="$display/@name" /></li>
    </xsl:when>

    <!-- if this is the default lang (and no correct lang exists), output this -->
    <xsl:when test="generate-id() = generate-id($default) and not($display)">
      <li><xsl:value-of select="$default/@name" /></li>
    </xsl:when>

    <!-- there is no "otherwise" - all other cases shall not produce output -->
  </xsl:choose>
</xsl:template>

这样,您可以通过传入正确的参数值轻松配置样式表的输出。

示例:http://www.xmlplayground.com/jv3TvQ