Саксонская функция расширения в узле возврата Java - PullRequest
0 голосов
/ 05 октября 2019

Я пытаюсь реализовать пользовательскую функцию, используя Saxon, как определено здесь-> https://specifications.xbrl.org/registries/functions-registry-1.0/80132%20xfi.identifier/80132%20xfi.identifier%20function.html

public class IdentifierFunction implements ExtensionFunction {

    public QName getName() {
        return new QName("http://www.xbrl.org/2005/function/instance", "identifier");
    }

    public SequenceType getResultType() {
        return SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE);
    }

    public net.sf.saxon.s9api.SequenceType[] getArgumentTypes() {
        return new SequenceType[] { SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE) };
    }

    public XdmValue call(XdmValue[] arguments) throws SaxonApiException {
        String arg = ((XdmAtomicValue) arguments[0].itemAt(0)).getStringValue();
        String newExpression="(//xbrli:xbrl/xbrli:context[@id=("+arg+"/@contextRef"+")])[1]/xbrli:entity/xbrli:identifier";
        String nodeString=this.getxPathResolver().resolveNode(this.getXbrl(),newExpression);
        return new XdmAtomicValue(nodeString);
    }
}

resolNode () выше кода реализован следующим образом

public String resolveNode(byte[] xbrlBytes, String expressionValue) {
        // 1. Instantiate an XPathFactory.
        javax.xml.xpath.XPathFactory factory = new XPathFactoryImpl();

        // 2. Use the XPathFactory to create a new XPath object
        javax.xml.xpath.XPath xpath = factory.newXPath();

        NamespaceContext ctx = new NamespaceContext() {
            @Override
            public String getNamespaceURI(String aPrefix) {
                if (aPrefix.equals("xfi"))
                    return "http://www.xbrl.org/2005/function/instance";
                else if (aPrefix.equals("xs"))
                    return "http://www.w3.org/2001/XMLSchema";
                else if (aPrefix.equals("xbrli"))
                    return "http://www.xbrl.org/2003/instance";
                else
                    return null;
            }

            @Override
            public Iterator getPrefixes(String val) {
                throw new UnsupportedOperationException();
            }

            @Override
            public String getPrefix(String uri) {
                throw new UnsupportedOperationException();
            }
        };
        xpath.setNamespaceContext(ctx);
        try {
            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
            Document someXML = documentBuilder.parse(new InputSource(new StringReader(new String(xbrlBytes))));

            // 3. Compile an XPath string into an XPathExpression
            javax.xml.xpath.XPathExpression expression = xpath.compile(expressionValue);
            Object result = expression.evaluate(someXML, XPathConstants.NODE);
            // 4. Evaluate the XPath expression on an input document
            Node nodes = (Node) result;
            return nodeToString(nodes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

Когда я оцениваю xfi: идентификатор (аргументы), я получаю строку, как показано ниже:

<xbrli:identifier xmlns:xbrli="http://www.xbrl.org/2003/instance"
                  xmlns:iso4217="http://www.xbrl.org/2003/iso4217"
                  xmlns:jenv-bw2-dim="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-axes"
                  xmlns:jenv-bw2-dm="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-domains"
                  xmlns:jenv-bw2-i="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-data"
                  xmlns:kvk-i="http://www.nltaxonomie.nl/nt13/kvk/20181212/dictionary/kvk-data"
                  xmlns:link="http://www.xbrl.org/2003/linkbase"
                  xmlns:nl-cd="http://www.nltaxonomie.nl/nt13/sbr/20180301/dictionary/nl-common-data"
                  xmlns:rj-i="http://www.nltaxonomie.nl/nt13/rj/20181212/dictionary/rj-data"
                  xmlns:rj-t="http://www.nltaxonomie.nl/nt13/rj/20181212/dictionary/rj-tuples"
                  xmlns:xbrldi="http://xbrl.org/2006/xbrldi"
                  xmlns:xlink="http://www.w3.org/1999/xlink"
                  scheme="http://www.kvk.nl/kvk-id">62394207</xbrli:identifier>

Однако я хочу оценить функцию число (xfi: идентификатор (аргументы))

Это приводит к NaN , что очевидно, поскольку полная строка узла не может быть преобразована в число. Я думаю, мне нужно изменить свою функцию, чтобы она возвращала Node. Однако я не уверен, как это сделать. Я попробовал Google, а также посмотрел на саксонскую документацию, но пока не повезло. Кто-нибудь может мне помочь? По сути, пользовательская функция должна возвращать узел элемента в соответствии с определением. и когда я использую число (xfi: идентификатор), оно должно дать мне 62394207 в этом случае.

С уважением,

Venky

1 Ответ

0 голосов
/ 05 октября 2019

Во-первых, спецификация XBRL для функции, по-видимому, подразумевает, что функция ожидает узел в качестве аргумента и возвращает узел в качестве результата, но в вашей реализации getArgumentTypes () и getResultType () определяют тип как xs: string - такэто нужно изменить.

И функция должна возвращать XdmNode, который является подклассом XdmValue.

Далее, очень неэффективно создавать DocumentBuilderFactory и XPathFactory, создавая дерево документов XMLи компилирование выражения XPath каждый раз, когда выполняется ваша функция. Я сильно подозреваю, что ничего из этого не требуется.

Вместо того, чтобы this.getXbrl () возвращал необработанный лексический документ как byte [], пусть он возвращает предварительно скомпонованный XdmNode, представляющий дерево документа. И тогда я хотел бы предложить, чтобы вместо выбора в этом дереве с помощью XPath вы использовали саксонский API-интерфейс навигации, похожий на linq. Если этот XdmNode находится в переменной «root», то выражение XPath

//xbrli:xbrl/xbrli:context[@id=("+arg+"/@contextRef"+")

преобразуется в нечто вроде

root.select(descendant("xbrl").then(child("context)).where(attributeEq("id", arg))

(за исключением того, что я не совсем уверен, что вы передаетеas arg, чтобы ваше XPath-выражение имело смысл).

Но вы можете использовать XPath, если хотите;просто используйте интерфейсы Saxon s9api для XPath и убедитесь, что выражение XPath скомпилировано только один раз и используется повторно. Тогда просто получить XdmNode как результат вашего выражения XPath, который может быть возвращен непосредственно как результат вашей функции расширения.

...