Как выполнить проверку схемы, чтобы получить недостающие ссылки с помощью SaxonJS

#node.js #saxon-js

Вопрос:

Если у меня есть простой xsd-файл и простой xml-файл, может ли SaxonJS показать, какие элементы и какие атрибуты в xml не определены в xsd?

Я искал примеры, но пока ничего не смог найти.

Обновить

Я также приму ответ с кодом js (узел), который использует saxon-js для обхода xml-ресурса и проверяет элементы и атрибуты (не нужно проверять значения атрибутов) в xsd-ресурсе.

В какой-то степени эффективным способом.

Комментарии:

1. (На основе схемы) проверка не является особенностью Saxon-JS, насколько мне известно. Проверка на основе схемы-это то, что предоставляет Saxon EE для Java, .NET или C/C , но не Saxon-JS.

2. Можете ли вы показать небольшую, но репрезентативную схему и образец экземпляра? «Простой файл xsd» легко сказать, но, на мой взгляд, большинство схем не являются «простыми», мощность и гибкость вложенности и объединения различных вариантов типов, частиц затрудняют создание чего-то простого и простого в XSLT. Я думаю, что у Saxonica есть собственный валидатор схем, реализованный в XSLT, но я понятия не имею, захотят ли они его коммерциализировать и сможет ли Saxon-JS справиться с этим. Возможно, имеет смысл связаться с ними напрямую по адресу saxonica.plan.io/projects/saxon-js если здесь никто не появится.

3. Кроме того, «какие элементы и атрибуты в XML не определены» является расплывчатым, оно может быть легко использовать ключ в схеме найти foo объявление элемента для foo экземпляра образца, но это не говорит что ли конкретное объявление находится в правильном месте для экземпляра элемента, чтобы быть действительным.

4. @MartinHonnen Вы хотите сказать, что saxon-js не загружает ресурс xsd как xsd? Но так же, как xml? Я предположил, что после загрузки xsd вы можете искать элементы в какой-то древовидной структуре

5. Я не уверен, где вы ожидаете или видите обработку XSD в реализации XPath 3.1 и XSLT 3.0, такой как Saxon-JS, если только она не поддерживает XSLT и XPath с учетом схемы, чего, насколько я знаю, не делает Saxon-JS. Таким образом, анализ/обработка XSD как любого XML-документа с помощью XSLT/XPath представляется возможной, но, конечно, не в качестве комплексного инструмента для замены средства проверки схемы или объектной модели схемы.

Ответ №1:

Чтобы просто проверить наличие xs:element элемента в схеме, достаточно ключа, то же самое для xs:attribute . Но все это зависит от использования простых xs:element name="foo" и xs:attribute name="att1" деклараций и никоим образом не проверяет вложенность или структуру:

 <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:key name="element-by-name" match="xs:element" use="QName(/*/@targetNamespace, @name)"/>
  
  <xsl:key name="attribute-by-name" match="xs:attribute" use="QName(/*/@targetNamespace, @name)"/>
  
  <xsl:template match="*[not(key('element-by-name', node-name(), $schema-doc))]">
    <element-not-declared>
      <name>{node-name()}</name>
      <path>{path()}</path>
    </element-not-declared>
    <xsl:next-match/>
  </xsl:template>
  
  <xsl:template match="@*[not(key('attribute-by-name', node-name(), $schema-doc))]">
    <attribute-not-declared>
      <name>{node-name()}</name>
      <path>{path()}</path>
    </attribute-not-declared>
  </xsl:template>

  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>
  
  <xsl:param name="schema-doc">
    <xs:schema>
      <xs:element name="root">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="items">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="item" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:element name="foo" type="xs:string"/>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  </xsl:param>

</xsl:stylesheet>
 

Ввод образца

 <?xml version="1.0" encoding="utf-8"?>
<root>
  <items count="1">
    <item>
      <foo>foo 1</foo>
      <bar>bar 1</bar>
    </item>
  </items>
</root>
 

при запуске с Saxon-JS 2.3 в браузере выдает

     <attribute-not-declared>
       <name>count</name>
       <path>/Q{}root[1]/Q{}items[1]/@count</path>
    </attribute-not-declared>
    <element-not-declared>
       <name>bar</name>
       <path>/Q{}root[1]/Q{}items[1]/Q{}item[1]/Q{}bar[1]</path>
    </element-not-declared>
    <!--Run with Saxon-JS 2.3 Browser-->
 

но я проверил, что это работает с «Saxon-JS 2.3 Node.js» также.

Таким образом, это находит некоторые элементы или атрибуты, для которых не найдено соответствующего объявления, на основе ключей, используемых в схеме. Это просто поверхностный подход, даже без учета сложностей пространств имен и формы элементов или формы атрибутов и пространств имен.

Чтобы запустить код XSLT 3 с помощью SaxonJS, вы можете либо запустить XSLT, SaxonJS.XPath.evaluate вызвав функцию XPath 3.1 transform , как показано ниже, либо сначала использовать xslt3 инструмент командной строки для экспорта XSLT в SEF/JSON, который затем можно запустить с помощью SaxonJS.transform .

 const SaxonJS = require("saxon-js");

const xml = `<?xml version="1.0" encoding="utf-8"?>
<root>
  <items count="1">
    <item>
      <foo>foo 1</foo>
      <bar>bar 1</bar>
    </item>
  </items>
</root>`;

const xsd = `<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:key name="element-by-name" match="xs:element" use="QName(/*/@targetNamespace, @name)"/>
  
  <xsl:key name="attribute-by-name" match="xs:attribute" use="QName(/*/@targetNamespace, @name)"/>
  
  <xsl:template match="*[not(key('element-by-name', node-name(), $schema-doc))]">
    <element-not-declared>
      <name>{node-name()}</name>
      <path>{path()}</path>
    </element-not-declared>
    <xsl:next-match/>
  </xsl:template>
  
  <xsl:template match="@*[not(key('attribute-by-name', node-name(), $schema-doc))]">
    <attribute-not-declared>
      <name>{node-name()}</name>
      <path>{path()}</path>
    </attribute-not-declared>
  </xsl:template>

  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>
  
  <xsl:param name="schema-doc">
    <xs:schema>
      <xs:element name="root">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="items">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="item" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:element name="foo" type="xs:string"/>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  </xsl:param>

</xsl:stylesheet>`;


const result = SaxonJS.XPath.evaluate(`
  transform(
    map {
      'source-node' : parse-xml($xml),
      'stylesheet-text' : $xsd,
      'delivery-format' : 'serialized'
      }
  )?output`,
  [],
  {
    params : { xml : xml, xsd : xsd }
  }
);

console.log(result);
 

Выход

 <?xml version="1.0" encoding="UTF-8"?>
<attribute-not-declared>
   <name>count</name>
   <path>/Q{}root[1]/Q{}items[1]/@count</path>
</attribute-not-declared>
<element-not-declared>
   <name>bar</name>
   <path>/Q{}root[1]/Q{}items[1]/Q{}item[1]/Q{}bar[1]</path>
</element-not-declared>
<!--Run with Saxon-JS 2.3 Node.js-->
 

Комментарии:

1. Честно говоря: я как бы ищу «код js (узел)»

2. Я еще не поблагодарил вас за ваш (подробный) ответ. Спасибо! Это очень полезно. К сожалению, когда я увидел, что вы добавили код js, я больше не мог присуждать награду.