xpath表达式强制返回缺少的节点

时间:2014-05-22 08:23:41

标签: xml xpath

<matrix id="2x2withNulls">
    <row>
        <column num="1">346</column>
    </row>
    <row>
        <column num="1">444</column>
        <column num="2">56</column>
    </row>
</matrix>

我需要迭代整个矩阵,有没有办法强制表达式创建一个null的节点?

理想情况下,/matrix/row/column会返回四个预期的节点。

/matrix/row/column[as many as max(foreach /matrix/column/)],必要时重复 要么 /matrix/row/column[not(exists num where exists in other colum)-> create it]

我只能使用一个表达式,因为表达式是第三方应用程序的参数。

也许必须有一种方法强制为第一行重复结果列num1,所以它总是返回max(列),即使它们是半空行中最后一个existsintg列的重复。

3 个答案:

答案 0 :(得分:4)

&#34;选择缺席节点的概念&#34;是一个有趣的,但可能会导致你走错路。正如一位哲学家曾经说过的上帝,存在不是一个谓词;你不能选择所有不存在的节点。

棘手的一点是你的陈述&#34;我只能使用一个表达式,因为表达式是第三方应用程序的参数。&#34;这似乎排除了XSLT,尽管您在问题中包含了XSLT标记。所以我认为更准确地了解约束会很好。

我会稍微调整一下Erat的解决方案:

return <matrix> {
  $matrix/@*,
  for $row in $matrix/row
  return <row> {
    for $i in 1 to 2
    return ($row/column[@num=$i], <column num="{$i}"/>)[1]
  } </row>
}</matrix>

答案 1 :(得分:3)

如果您自己创建xml,则可以首先确保对xsd sequence minOccursmaxOccurs的{​​{1}}进行验证。设置为所需的计数;这样做可以限制节点本身的数量。

阅读xsd sequence here

如果您从第三方应用程序中获取此xml,但想要包含空节点,则可以使用LinqToXml(假设您可以在项目中使用C#并假设xDoc是包含XDocument)的xml

public void AddEmptyNodesIf(XDocument xDoc, int targetElementCount = 4)
{
    XElement e = new XElement("column");
    e.Add(new XAttribute("num", null));

    foreach (XElement row in xDoc.Elements("row"))
    {
        int lastOccurringId = int.Parse(row.Elements("column")
            .Last().Attribute("num").Value);

        while (row.Elements("column").Count() < targetElementCount)
        {
            lastOccurringId++;
            e.Attribute("num").Value = lastOccurringId.ToString();
            row.Add(e);
        }
    }
}

请注意,我没有对此进行测试,但即使它没有完全奏效,您也会得到它的一般要点。

答案 2 :(得分:2)

您必须重建结果,并在必要时创建新列。

let $matrix :=
  <matrix id="2x2withNulls">
    <row>
      <column num="1">346</column>
    </row>
    <row>
      <column num="1">444</column>
      <column num="2">56</column>
    </row>
  </matrix>

return element matrix {
  $matrix/@*,
  for $row in $matrix/row
  return element row {
    for $i in 1 to 2
    return
      if ($row/column[@num=$i])
      then $row/column[@num=$i]
      else element column { attribute num { $i }}
  }
}